summaryrefslogtreecommitdiffstats
path: root/dom/events/test
diff options
context:
space:
mode:
Diffstat (limited to 'dom/events/test')
-rw-r--r--dom/events/test/.eslintrc.js9
-rw-r--r--dom/events/test/browser.ini17
-rw-r--r--dom/events/test/browser_alt_keyup_in_content.js321
-rw-r--r--dom/events/test/browser_beforeinput_by_execCommand_in_contentscript.js108
-rw-r--r--dom/events/test/browser_bug1539497.js28
-rw-r--r--dom/events/test/browser_mouse_enterleave_switch_tab.js158
-rw-r--r--dom/events/test/browser_shortcutkey_modifier_conflicts_with_content_accesskey_modifier.js102
-rw-r--r--dom/events/test/bug1017086_inner.html41
-rw-r--r--dom/events/test/bug226361_iframe.xhtml47
-rw-r--r--dom/events/test/bug299673.js150
-rw-r--r--dom/events/test/bug322588-popup.html1
-rw-r--r--dom/events/test/bug415498-doc1.html15
-rw-r--r--dom/events/test/bug415498-doc2.html15
-rw-r--r--dom/events/test/bug418986-3.js83
-rw-r--r--dom/events/test/bug426082.html116
-rw-r--r--dom/events/test/bug545268.html1
-rw-r--r--dom/events/test/bug574663.html3
-rw-r--r--dom/events/test/bug591249_iframe.xhtml33
-rw-r--r--dom/events/test/bug602962.xhtml8
-rw-r--r--dom/events/test/bug607464.html3
-rw-r--r--dom/events/test/bug656379-1.html186
-rw-r--r--dom/events/test/chrome.ini30
-rw-r--r--dom/events/test/empty.js0
-rw-r--r--dom/events/test/error_event_worker.js19
-rw-r--r--dom/events/test/event_leak_utils.js84
-rw-r--r--dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html2
-rw-r--r--dom/events/test/file_bug1446834.html96
-rw-r--r--dom/events/test/file_bug1484371.html94
-rw-r--r--dom/events/test/file_bug679494.html8
-rw-r--r--dom/events/test/file_coalesce_touchmove.html169
-rw-r--r--dom/events/test/file_empty.html1
-rw-r--r--dom/events/test/file_event_screenXY.html20
-rw-r--r--dom/events/test/file_focus_blur_on_click_in_cross_origin_iframe.html23
-rw-r--r--dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html23
-rw-r--r--dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html30
-rw-r--r--dom/events/test/file_mouse_enterleave.html40
-rw-r--r--dom/events/test/mochitest.ini251
-rw-r--r--dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_1.html63
-rw-r--r--dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_2.html64
-rw-r--r--dom/events/test/pointerevents/bug_1420589_iframe1.html17
-rw-r--r--dom/events/test/pointerevents/bug_1420589_iframe2.html17
-rw-r--r--dom/events/test/pointerevents/file_pointercapture_xorigin_iframe.html62
-rw-r--r--dom/events/test/pointerevents/file_pointercapture_xorigin_iframe_pointerlock.html111
-rw-r--r--dom/events/test/pointerevents/file_test_trigger_fullscreen.html1
-rw-r--r--dom/events/test/pointerevents/iframe.html7
-rw-r--r--dom/events/test/pointerevents/mochitest.ini116
-rw-r--r--dom/events/test/pointerevents/mochitest_support_external.js286
-rw-r--r--dom/events/test/pointerevents/mochitest_support_internal.js125
-rw-r--r--dom/events/test/pointerevents/pointerevent_utils.js60
-rw-r--r--dom/events/test/pointerevents/readme.md9
-rw-r--r--dom/events/test/pointerevents/test_bug1285128.html53
-rw-r--r--dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_1.html30
-rw-r--r--dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_2.html30
-rw-r--r--dom/events/test/pointerevents/test_bug1303704.html135
-rw-r--r--dom/events/test/pointerevents/test_bug1315862.html68
-rw-r--r--dom/events/test/pointerevents/test_bug1323158.html93
-rw-r--r--dom/events/test/pointerevents/test_bug1403055.html92
-rw-r--r--dom/events/test/pointerevents/test_bug1420589_1.html103
-rw-r--r--dom/events/test/pointerevents/test_bug1420589_2.html120
-rw-r--r--dom/events/test/pointerevents/test_bug1420589_3.html113
-rw-r--r--dom/events/test/pointerevents/test_getCoalescedEvents.html92
-rw-r--r--dom/events/test/pointerevents/test_multiple_touches.html189
-rw-r--r--dom/events/test/pointerevents/test_pointercapture_remove_iframe.html80
-rw-r--r--dom/events/test/pointerevents/test_pointercapture_xorigin_iframe.html54
-rw-r--r--dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html170
-rw-r--r--dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html55
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_attributes_hoverable_pointers-manual.html53
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_attributes_nohover_pointers-manual.html26
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_boundary_events_in_capturing-manual.html46
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_change-touch-action-onpointerdown_touch-manual.html39
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_constructor.html26
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_drag_interaction-manual.html38
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_movementxy-manual.html53
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_multiple_primary_pointers_boundary_events-manual.html31
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_pointerId_scope-manual.html27
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_pointercancel_touch-manual.html30
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_after_pointercancel_touch-manual.html30
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_pen-manual.html28
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_after_pointercancel_touch-manual.html30
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_pen-manual.html28
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_events_to_original_target-manual.html49
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_onpointercancel_touch-manual.html30
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_pointerup_touch.html29
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_sequence_at_implicit_release_on_drag-manual.html27
-rw-r--r--dom/events/test/pointerevents/test_wpt_pointerevent_setpointercapture_pointerup_touch.html26
-rw-r--r--dom/events/test/pointerevents/test_wpt_touch_action.html103
-rw-r--r--dom/events/test/pointerevents/touch_action_helpers.js263
-rw-r--r--dom/events/test/pointerevents/wpt/compat/pointerevent_touch-action_two-finger_interaction-manual.html102
-rw-r--r--dom/events/test/pointerevents/wpt/html/pointerevent_drag_interaction-manual.html103
-rw-r--r--dom/events/test/pointerevents/wpt/idlharness.html104
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_attributes_hoverable_pointers-manual.html143
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_attributes_nohover_pointers-manual.html126
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_boundary_events_in_capturing-manual.html97
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_change-touch-action-onpointerdown_touch-manual.html135
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_constructor.html106
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_multiple_primary_pointers_boundary_events-manual.html145
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_pointerId_scope-manual.html82
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_pointercancel_touch-manual.html77
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_pointerleave_after_pointercancel_touch-manual.html66
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_pointerleave_pen-manual.html58
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_pointerout_after_pointercancel_touch-manual.html67
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_pointerout_pen-manual.html57
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html137
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html71
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_pointerup_touch.html102
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_click-manual.html83
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.html84
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_setpointercapture_pointerup_touch.html102
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_styles.css112
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_support.js333
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-auto-css_touch-manual.html129
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-button-test_touch-manual.html110
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-illegal.html67
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html117
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-none_touch-manual.html112
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html112
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html117
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html133
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_parent-none_touch-manual.html112
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-keyboard-manual.html124
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-mouse-manual.html130
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-none-css_touch-manual.html111
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-down-css_touch-manual.html114
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-left-css_touch-manual.html114
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-right-css_touch-manual.html114
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-up-css_touch-manual.html114
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-css_touch-manual.html106
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html111
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y_touch-manual.html126
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-y-css_touch-manual.html106
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-span-test_touch-manual.html114
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-svg-test_touch-manual.html122
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-table-test_touch-manual.html145
-rw-r--r--dom/events/test/pointerevents/wpt/pointerevent_touch-action-verification.html91
-rw-r--r--dom/events/test/pointerevents/wpt/pointerlock/pointerevent_movementxy-manual.html99
-rw-r--r--dom/events/test/pointerevents/wpt/pointerlock/resources/pointerevent_movementxy-iframe.html8
-rw-r--r--dom/events/test/pointerevents/wpt/resources/pointerevent_attributes_hoverable_pointers-iframe.html10
-rw-r--r--dom/events/test/pointerevents/wpt/resources/pointerevent_pointerId_scope-iframe.html35
-rw-r--r--dom/events/test/test_DataTransferItemList.html234
-rw-r--r--dom/events/test/test_accel_virtual_modifier.html90
-rw-r--r--dom/events/test/test_addEventListenerExtraArg.html31
-rw-r--r--dom/events/test/test_all_synthetic_events.html470
-rw-r--r--dom/events/test/test_bug1003432.html45
-rw-r--r--dom/events/test/test_bug1003432.js31
-rw-r--r--dom/events/test/test_bug1013412.html111
-rw-r--r--dom/events/test/test_bug1017086_disable.html41
-rw-r--r--dom/events/test/test_bug1017086_enable.html43
-rw-r--r--dom/events/test/test_bug1037990.html61
-rw-r--r--dom/events/test/test_bug1079236.html66
-rw-r--r--dom/events/test/test_bug1127588.html61
-rw-r--r--dom/events/test/test_bug1128787-1.html53
-rw-r--r--dom/events/test/test_bug1128787-2.html54
-rw-r--r--dom/events/test/test_bug1128787-3.html53
-rw-r--r--dom/events/test/test_bug1145910.html54
-rw-r--r--dom/events/test/test_bug1150308.html49
-rw-r--r--dom/events/test/test_bug1248459.html58
-rw-r--r--dom/events/test/test_bug1264380.html82
-rw-r--r--dom/events/test/test_bug1298970.html33
-rw-r--r--dom/events/test/test_bug1304044.html133
-rw-r--r--dom/events/test/test_bug1305458.html50
-rw-r--r--dom/events/test/test_bug1327798.html47
-rw-r--r--dom/events/test/test_bug1332699.html37
-rw-r--r--dom/events/test/test_bug1339758.html80
-rw-r--r--dom/events/test/test_bug1369072.html37
-rw-r--r--dom/events/test/test_bug1412775.xhtml66
-rw-r--r--dom/events/test/test_bug1429572.html43
-rw-r--r--dom/events/test/test_bug1446834.html33
-rw-r--r--dom/events/test/test_bug1447993.html42
-rw-r--r--dom/events/test/test_bug1484371.html27
-rw-r--r--dom/events/test/test_bug1518442.html49
-rw-r--r--dom/events/test/test_bug1534562.html51
-rw-r--r--dom/events/test/test_bug1539497.html30
-rw-r--r--dom/events/test/test_bug1581192.html66
-rw-r--r--dom/events/test/test_bug1673434.html75
-rw-r--r--dom/events/test/test_bug1686716.html28
-rw-r--r--dom/events/test/test_bug226361.xhtml82
-rw-r--r--dom/events/test/test_bug238987.html279
-rw-r--r--dom/events/test/test_bug288392.html103
-rw-r--r--dom/events/test/test_bug299673-1.html61
-rw-r--r--dom/events/test/test_bug299673-2.html60
-rw-r--r--dom/events/test/test_bug322588.html66
-rw-r--r--dom/events/test/test_bug328885.html132
-rw-r--r--dom/events/test/test_bug336682.js96
-rw-r--r--dom/events/test/test_bug336682_1.html55
-rw-r--r--dom/events/test/test_bug336682_2.xhtml59
-rw-r--r--dom/events/test/test_bug367781.html53
-rw-r--r--dom/events/test/test_bug379120.html55
-rw-r--r--dom/events/test/test_bug402089.html67
-rw-r--r--dom/events/test/test_bug405632.html34
-rw-r--r--dom/events/test/test_bug409604.html379
-rw-r--r--dom/events/test/test_bug412567.html47
-rw-r--r--dom/events/test/test_bug415498.xhtml95
-rw-r--r--dom/events/test/test_bug418986-3.html25
-rw-r--r--dom/events/test/test_bug418986-3.xhtml27
-rw-r--r--dom/events/test/test_bug422132.html124
-rw-r--r--dom/events/test/test_bug426082.html30
-rw-r--r--dom/events/test/test_bug427537.html61
-rw-r--r--dom/events/test/test_bug428988.html44
-rw-r--r--dom/events/test/test_bug432698.html223
-rw-r--r--dom/events/test/test_bug443985.html76
-rw-r--r--dom/events/test/test_bug447736.html47
-rw-r--r--dom/events/test/test_bug448602.html220
-rw-r--r--dom/events/test/test_bug450876.html47
-rw-r--r--dom/events/test/test_bug456273.html41
-rw-r--r--dom/events/test/test_bug457672.html55
-rw-r--r--dom/events/test/test_bug489671.html55
-rw-r--r--dom/events/test/test_bug493251.html181
-rw-r--r--dom/events/test/test_bug508479.html110
-rw-r--r--dom/events/test/test_bug517851.html122
-rw-r--r--dom/events/test/test_bug524674.xhtml130
-rw-r--r--dom/events/test/test_bug534833.html156
-rw-r--r--dom/events/test/test_bug545268.html129
-rw-r--r--dom/events/test/test_bug547996-1.html87
-rw-r--r--dom/events/test/test_bug547996-2.xhtml125
-rw-r--r--dom/events/test/test_bug556493.html74
-rw-r--r--dom/events/test/test_bug563329.html82
-rw-r--r--dom/events/test/test_bug574663.html193
-rw-r--r--dom/events/test/test_bug586961.xhtml46
-rw-r--r--dom/events/test/test_bug591249.xhtml73
-rw-r--r--dom/events/test/test_bug591815.html68
-rw-r--r--dom/events/test/test_bug593959.html60
-rw-r--r--dom/events/test/test_bug602962.xhtml87
-rw-r--r--dom/events/test/test_bug603008.html556
-rw-r--r--dom/events/test/test_bug605242.html58
-rw-r--r--dom/events/test/test_bug607464.html84
-rw-r--r--dom/events/test/test_bug613634.html90
-rw-r--r--dom/events/test/test_bug615597.html39
-rw-r--r--dom/events/test/test_bug617528.xhtml94
-rw-r--r--dom/events/test/test_bug624127.html35
-rw-r--r--dom/events/test/test_bug635465.html90
-rw-r--r--dom/events/test/test_bug641477.html37
-rw-r--r--dom/events/test/test_bug648573.html120
-rw-r--r--dom/events/test/test_bug650493.html215
-rw-r--r--dom/events/test/test_bug656379-1.html30
-rw-r--r--dom/events/test/test_bug656379-2.html115
-rw-r--r--dom/events/test/test_bug656954.html42
-rw-r--r--dom/events/test/test_bug659071.html39
-rw-r--r--dom/events/test/test_bug659350.html111
-rw-r--r--dom/events/test/test_bug662678.html153
-rw-r--r--dom/events/test/test_bug667612.html38
-rw-r--r--dom/events/test/test_bug667919-1.html41
-rw-r--r--dom/events/test/test_bug679494.xhtml36
-rw-r--r--dom/events/test/test_bug684208.html80
-rw-r--r--dom/events/test/test_bug687787.html616
-rw-r--r--dom/events/test/test_bug689564.html65
-rw-r--r--dom/events/test/test_bug698929.html47
-rw-r--r--dom/events/test/test_bug704423.html40
-rw-r--r--dom/events/test/test_bug741666.html176
-rw-r--r--dom/events/test/test_bug812744.html37
-rw-r--r--dom/events/test/test_bug822898.html343
-rw-r--r--dom/events/test/test_bug855741.html90
-rw-r--r--dom/events/test/test_bug864040.html87
-rw-r--r--dom/events/test/test_bug924087.html45
-rw-r--r--dom/events/test/test_bug930374-chrome.html57
-rw-r--r--dom/events/test/test_bug930374-content.html70
-rw-r--r--dom/events/test/test_bug944011.html52
-rw-r--r--dom/events/test/test_bug944847.html42
-rw-r--r--dom/events/test/test_bug946632.html162
-rw-r--r--dom/events/test/test_bug967796.html243
-rw-r--r--dom/events/test/test_bug985988.html89
-rw-r--r--dom/events/test/test_bug998809.html35
-rw-r--r--dom/events/test/test_click_on_reframed_generated_text.html32
-rw-r--r--dom/events/test/test_click_on_restyled_element.html51
-rw-r--r--dom/events/test/test_clickevent_on_input.html108
-rw-r--r--dom/events/test/test_coalesce_touchmove.html18
-rw-r--r--dom/events/test/test_continuous_wheel_events.html3290
-rw-r--r--dom/events/test/test_dblclick_explicit_original_target.html52
-rw-r--r--dom/events/test/test_deviceSensor.html136
-rw-r--r--dom/events/test/test_disabled_events.html40
-rw-r--r--dom/events/test/test_dnd_with_modifiers.html78
-rw-r--r--dom/events/test/test_dom_activate_event.html91
-rw-r--r--dom/events/test/test_dom_keyboard_event.html548
-rw-r--r--dom/events/test/test_dom_mouse_event.html143
-rw-r--r--dom/events/test/test_dom_storage_event.html62
-rw-r--r--dom/events/test/test_dom_wheel_event.html835
-rw-r--r--dom/events/test/test_draggableprop.html89
-rw-r--r--dom/events/test/test_dragstart.html631
-rw-r--r--dom/events/test/test_error_events.html71
-rw-r--r--dom/events/test/test_eventTimeStamp.html116
-rw-r--r--dom/events/test/test_event_handler_cc.html77
-rw-r--r--dom/events/test/test_event_screenXY_in_cross_origin_iframe.html110
-rw-r--r--dom/events/test/test_eventctors.html936
-rw-r--r--dom/events/test/test_eventctors.xhtml49
-rw-r--r--dom/events/test/test_eventctors_sensors.html110
-rw-r--r--dom/events/test/test_eventhandler_scoping.html17
-rw-r--r--dom/events/test/test_focus_abspos.html32
-rw-r--r--dom/events/test/test_focus_blur_on_click_in_cross_origin_iframe.html119
-rw-r--r--dom/events/test/test_focus_blur_on_click_in_deep_cross_origin_iframe.html146
-rw-r--r--dom/events/test/test_hover_mouseleave.html47
-rw-r--r--dom/events/test/test_legacy_event.html297
-rw-r--r--dom/events/test/test_legacy_non-primary_click.html53
-rw-r--r--dom/events/test/test_legacy_touch_api.html65
-rw-r--r--dom/events/test/test_marquee_events.html31
-rw-r--r--dom/events/test/test_messageEvent.html79
-rw-r--r--dom/events/test/test_messageEvent_init.html25
-rw-r--r--dom/events/test/test_mouse_capture_iframe.html67
-rw-r--r--dom/events/test/test_mouse_enterleave_iframe.html272
-rw-r--r--dom/events/test/test_moz_mouse_pixel_scroll_event.html1363
-rw-r--r--dom/events/test/test_offsetxy.html98
-rw-r--r--dom/events/test/test_onerror_handler_args.html36
-rw-r--r--dom/events/test/test_passive_listeners.html118
-rw-r--r--dom/events/test/test_paste_image.html192
-rw-r--r--dom/events/test/test_slotted_mouse_event.html97
-rw-r--r--dom/events/test/test_slotted_text_click.html72
-rw-r--r--dom/events/test/test_text_event_in_content.html69
-rw-r--r--dom/events/test/test_unbound_before_in_active_chain.html38
-rw-r--r--dom/events/test/test_use_conflated_keypress_event_model_on_newer_Office_Online_Server.html65
-rw-r--r--dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html88
-rw-r--r--dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html75
-rw-r--r--dom/events/test/test_wheel_default_action.html39
-rw-r--r--dom/events/test/test_wheel_zoom_on_form_controls.html62
-rw-r--r--dom/events/test/window_bug1369072.html156
-rw-r--r--dom/events/test/window_bug1412775.xhtml8
-rw-r--r--dom/events/test/window_bug1429572.html345
-rw-r--r--dom/events/test/window_bug1447993.html239
-rw-r--r--dom/events/test/window_bug493251.html13
-rw-r--r--dom/events/test/window_bug617528.xhtml9
-rw-r--r--dom/events/test/window_bug659071.html69
-rw-r--r--dom/events/test/window_wheel_default_action.html3512
319 files changed, 38377 insertions, 0 deletions
diff --git a/dom/events/test/.eslintrc.js b/dom/events/test/.eslintrc.js
new file mode 100644
index 0000000000..317abe7b48
--- /dev/null
+++ b/dom/events/test/.eslintrc.js
@@ -0,0 +1,9 @@
+"use strict";
+
+module.exports = {
+ extends: [
+ "plugin:mozilla/browser-test",
+ "plugin:mozilla/chrome-test",
+ "plugin:mozilla/mochitest-test",
+ ],
+};
diff --git a/dom/events/test/browser.ini b/dom/events/test/browser.ini
new file mode 100644
index 0000000000..86ecc36462
--- /dev/null
+++ b/dom/events/test/browser.ini
@@ -0,0 +1,17 @@
+[DEFAULT]
+
+[browser_alt_keyup_in_content.js]
+skip-if = (os != 'linux' && os != 'win') || skip-if = !e10s
+
+[browser_beforeinput_by_execCommand_in_contentscript.js]
+support-files =
+ file_beforeinput_by_execCommand_in_contentscript.html
+ ../../../browser/base/content/test/general/head.js
+
+[browser_bug1539497.js]
+[browser_mouse_enterleave_switch_tab.js]
+support-files =
+ ../../../browser/base/content/test/general/dummy_page.html
+
+[browser_shortcutkey_modifier_conflicts_with_content_accesskey_modifier.js]
+skip-if = os != 'linux' && os != 'win' // Alt + D is defined only on Linux and Windows
diff --git a/dom/events/test/browser_alt_keyup_in_content.js b/dom/events/test/browser_alt_keyup_in_content.js
new file mode 100644
index 0000000000..e148800530
--- /dev/null
+++ b/dom/events/test/browser_alt_keyup_in_content.js
@@ -0,0 +1,321 @@
+"use strict";
+
+const { ContentTaskUtils } = ChromeUtils.import(
+ "resource://testing-common/ContentTaskUtils.jsm"
+);
+
+add_task(async function runTests() {
+ const menubar = document.getElementById("toolbar-menubar");
+ const autohide = menubar.getAttribute("autohide");
+ // This test requires that the window is active because of the limitation of
+ // menubar. Therefore, we should abort if the window becomes inactive during
+ // the tests.
+ let runningTests = true;
+ function onWindowActive(aEvent) {
+ // Don't warn after timed out.
+ if (runningTests && aEvent.target === window) {
+ info(
+ "WARNING: This window shouldn't have been inactivated during tests, but received an activated event!"
+ );
+ }
+ }
+ function onWindowInactive(aEvent) {
+ // Don't warn after timed out.
+ if (runningTests && aEvent.target === window) {
+ info(
+ "WARNING: This window should be active during tests, but inactivated!"
+ );
+ window.focus();
+ }
+ }
+ let menubarActivated = false;
+ function onMenubarActive() {
+ menubarActivated = true;
+ }
+ // In this test, menu popups shouldn't be open, but this helps avoiding
+ // intermittent failure after inactivating the menubar.
+ let popupEvents = 0;
+ function getPopupInfo(aPopupEventTarget) {
+ return `<${
+ aPopupEventTarget.nodeName
+ }${aPopupEventTarget.getAttribute("id") !== null ? ` id="${aPopupEventTarget.getAttribute("id")}"` : ""}>`;
+ }
+ function onPopupShown(aEvent) {
+ // Don't warn after timed out.
+ if (!runningTests) {
+ return;
+ }
+ popupEvents++;
+ info(
+ `A popup (${getPopupInfo(
+ aEvent.target
+ )}) is shown (visible popups: ${popupEvents})`
+ );
+ }
+ function onPopupHidden(aEvent) {
+ // Don't warn after timed out.
+ if (!runningTests) {
+ return;
+ }
+ if (popupEvents === 0) {
+ info(
+ `WARNING: There are some unexpected popups which may be not cleaned up by the previous test (${getPopupInfo(
+ aEvent.target
+ )})`
+ );
+ return;
+ }
+ popupEvents--;
+ info(
+ `A popup (${getPopupInfo(
+ aEvent.target
+ )}) is hidden (visible popups: ${popupEvents})`
+ );
+ }
+ try {
+ Services.prefs.setBoolPref("ui.key.menuAccessKeyFocuses", true);
+ // If this fails, you need to replace "KEY_Alt" with a variable whose
+ // value is considered from the pref.
+ is(
+ Services.prefs.getIntPref("ui.key.menuAccessKey"),
+ 18,
+ "This test assumes that Alt key activates the menubar"
+ );
+ window.addEventListener("activate", onWindowActive);
+ window.addEventListener("deactivate", onWindowInactive);
+ window.addEventListener("popupshown", onPopupShown);
+ window.addEventListener("popuphidden", onPopupHidden);
+ menubar.addEventListener("DOMMenuBarActive", onMenubarActive);
+ async function doTest(aTest) {
+ await new Promise(resolve => {
+ if (Services.focus.activeWindow === window) {
+ resolve();
+ return;
+ }
+ info(
+ `${aTest.description}: The testing window is inactive, trying to activate it...`
+ );
+ Services.focus.focusedWindow = window;
+ TestUtils.waitForCondition(() => {
+ if (Services.focus.activeWindow === window) {
+ resolve();
+ return true;
+ }
+ Services.focus.focusedWindow = window;
+ return false;
+ }, `${aTest.description}: Waiting the window is activated`);
+ });
+ info(`Start to test: ${aTest.description}...`);
+
+ async function ensureMenubarInactive() {
+ if (!menubar.querySelector("[_moz-menuactive=true]")) {
+ return;
+ }
+ info(`${aTest.description}: Inactivating the menubar...`);
+ let waitForMenuBarInactive = BrowserTestUtils.waitForEvent(
+ menubar,
+ "DOMMenuBarInactive"
+ );
+ EventUtils.synthesizeKey("KEY_Escape", {}, window);
+ await waitForMenuBarInactive;
+ await TestUtils.waitForCondition(() => {
+ return popupEvents === 0;
+ }, `${aTest.description}: Waiting for closing all popups`);
+ }
+
+ try {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: aTest.url,
+ },
+ async browser => {
+ info(`${aTest.description}: Waiting browser getting focus...`);
+ await SimpleTest.promiseFocus(browser);
+ await ensureMenubarInactive();
+ menubarActivated = false;
+
+ let keyupEventFiredInContent = false;
+ BrowserTestUtils.addContentEventListener(
+ browser,
+ "keyup",
+ () => {
+ keyupEventFiredInContent = true;
+ },
+ { capture: true },
+ event => {
+ return event.key === "Alt";
+ }
+ );
+
+ // For making sure adding the above content event listener and
+ // it'll get `keyup` event, let's run `SpecialPowers.spawn` and
+ // wait for focus in the content process.
+ info(
+ `${aTest.description}: Waiting content process getting focus...`
+ );
+ await SpecialPowers.spawn(
+ browser,
+ [aTest.description],
+ async aTestDescription => {
+ await ContentTaskUtils.waitForCondition(() => {
+ if (
+ content.browsingContext.isActive &&
+ content.document.hasFocus()
+ ) {
+ return true;
+ }
+ content.window.focus();
+ return false;
+ }, `${aTestDescription}: Waiting for content gets focus in content process`);
+ }
+ );
+
+ let waitForAllKeyUpEventsInChrome = new Promise(resolve => {
+ // Wait 2 `keyup` events in the main process. First one is
+ // synthesized one. The other is replay event from content.
+ let firstKeyUpEvent;
+ window.addEventListener(
+ "keyup",
+ function onKeyUpInChrome(event) {
+ if (!firstKeyUpEvent) {
+ firstKeyUpEvent = event;
+ return;
+ }
+ window.removeEventListener("keyup", onKeyUpInChrome, {
+ capture: true,
+ });
+ resolve();
+ },
+ { capture: true }
+ );
+ });
+ EventUtils.synthesizeKey("KEY_Alt", {}, window);
+ info(
+ `${aTest.description}: Waiting keyup events of Alt in chrome...`
+ );
+ await waitForAllKeyUpEventsInChrome;
+ info(`${aTest.description}: Waiting keyup event in content...`);
+ try {
+ await TestUtils.waitForCondition(() => {
+ return keyupEventFiredInContent;
+ }, `${aTest.description}: Waiting for content gets focus in chrome process`);
+ } catch (ex) {
+ ok(
+ false,
+ `${aTest.description}: Failed to synthesize Alt key press in the content process`
+ );
+ return;
+ }
+
+ if (aTest.expectMenubarActive) {
+ ok(
+ menubarActivated,
+ `${aTest.description}: Menubar should've been activated by the synthesized Alt key press`
+ );
+ } else {
+ // Wait some ticks to verify not receiving "DOMMenuBarActive" event.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 500));
+ ok(
+ !menubarActivated,
+ `${aTest.description}: Menubar should not have been activated by the synthesized Alt key press`
+ );
+ }
+ }
+ );
+ } catch (ex) {
+ ok(
+ false,
+ `${aTest.description}: Thrown an exception: ${ex.toString()}`
+ );
+ } finally {
+ await ensureMenubarInactive();
+ info(`End testing: ${aTest.description}`);
+ }
+ }
+
+ // Testcases for users who use collapsible menubar (by default)
+ menubar.setAttribute("autohide", "true");
+ await doTest({
+ description: "Testing menubar is shown by Alt keyup",
+ url: "data:text/html;charset=utf-8,<p>static page</p>",
+ expectMenubarActive: true,
+ });
+ await doTest({
+ description:
+ "Testing menubar is shown by Alt keyup when an <input> has focus",
+ url:
+ "data:text/html;charset=utf-8,<input>" +
+ '<script>document.querySelector("input").focus()</script>',
+ expectMenubarActive: true,
+ });
+ await doTest({
+ description:
+ "Testing menubar is shown by Alt keyup when an editing host has focus",
+ url:
+ "data:text/html;charset=utf-8,<p contenteditable></p>" +
+ '<script>document.querySelector("p[contenteditable]").focus()</script>',
+ expectMenubarActive: true,
+ });
+ await doTest({
+ description:
+ "Testing menubar won't be shown by Alt keyup due to suppressed by the page",
+ url:
+ "data:text/html;charset=utf-8,<p>dynamic page</p>" +
+ '<script>window.addEventListener("keyup", event => { event.preventDefault(); })</script>',
+ expectMenubarActive: false,
+ });
+
+ // Testcases for users who always show the menubar.
+ menubar.setAttribute("autohide", "false");
+ await doTest({
+ description: "Testing menubar is activated by Alt keyup",
+ url: "data:text/html;charset=utf-8,<p>static page</p>",
+ expectMenubarActive: true,
+ });
+ await doTest({
+ description:
+ "Testing menubar is activated by Alt keyup when an <input> has focus",
+ url:
+ "data:text/html;charset=utf-8,<input>" +
+ '<script>document.querySelector("input").focus()</script>',
+ expectMenubarActive: true,
+ });
+ await doTest({
+ description:
+ "Testing menubar is activated by Alt keyup when an editing host has focus",
+ url:
+ "data:text/html;charset=utf-8,<p contenteditable></p>" +
+ '<script>document.querySelector("p[contenteditable]").focus()</script>',
+ expectMenubarActive: true,
+ });
+ await doTest({
+ description:
+ "Testing menubar won't be activated by Alt keyup due to suppressed by the page",
+ url:
+ "data:text/html;charset=utf-8,<p>dynamic page</p>" +
+ '<script>window.addEventListener("keyup", event => { event.preventDefault(); })</script>',
+ expectMenubarActive: false,
+ });
+ runningTests = false;
+ } catch (ex) {
+ ok(
+ false,
+ `Aborting this test due to unexpected the exception (${ex.toString()})`
+ );
+ runningTests = false;
+ } finally {
+ if (autohide !== null) {
+ menubar.setAttribute("autohide", autohide);
+ } else {
+ menubar.removeAttribute("autohide");
+ }
+ Services.prefs.clearUserPref("ui.key.menuAccessKeyFocuses");
+ menubar.removeEventListener("DOMMenuBarActive", onMenubarActive);
+ window.removeEventListener("activate", onWindowActive);
+ window.removeEventListener("deactivate", onWindowInactive);
+ window.removeEventListener("popupshown", onPopupShown);
+ window.removeEventListener("popuphidden", onPopupHidden);
+ }
+});
diff --git a/dom/events/test/browser_beforeinput_by_execCommand_in_contentscript.js b/dom/events/test/browser_beforeinput_by_execCommand_in_contentscript.js
new file mode 100644
index 0000000000..f7b91bf27c
--- /dev/null
+++ b/dom/events/test/browser_beforeinput_by_execCommand_in_contentscript.js
@@ -0,0 +1,108 @@
+"use strict";
+
+async function installAndStartExtension() {
+ function contentScript() {
+ window.addEventListener("keydown", aEvent => {
+ console.log("keydown event is fired");
+ if (aEvent.defaultPrevented) {
+ return;
+ }
+ let selection = window.getSelection();
+ if (selection.isCollapsed) {
+ return;
+ }
+ if (aEvent.ctrlKey && aEvent.key === "k") {
+ document.execCommand("createLink", false, "http://example.com/");
+ aEvent.preventDefault();
+ }
+ });
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ content_scripts: [
+ {
+ js: ["content_script.js"],
+ matches: ["<all_urls>"],
+ run_at: "document_start",
+ },
+ ],
+ },
+ files: {
+ "content_script.js": contentScript,
+ },
+ });
+
+ await extension.startup();
+
+ return extension;
+}
+
+add_task(async function() {
+ await pushPrefs(["dom.input_events.beforeinput.enabled", true]);
+
+ const extension = await installAndStartExtension();
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "http://example.com/browser/dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html",
+ true
+ );
+
+ function runTest() {
+ var editor = content.document.querySelector("[contenteditable]");
+ editor.focus();
+ content.document.getSelection().selectAllChildren(editor);
+ var beforeinput;
+ editor.addEventListener("beforeinput", aEvent => {
+ beforeinput = aEvent;
+ });
+ editor.addEventListener("input", aEvent => {
+ if (!beforeinput) {
+ sendAsyncMessage("Test:BeforeInputInContentEditable", {
+ succeeded: false,
+ message: "No beforeinput event is fired",
+ });
+ return;
+ }
+ sendAsyncMessage("Test:BeforeInputInContentEditable", {
+ succeeded:
+ editor.innerHTML === '<a href="http://example.com/">abcdef</a>',
+ message: `editor.innerHTML=${editor.innerHTML}`,
+ });
+ });
+ }
+
+ try {
+ tab.linkedBrowser.messageManager.loadFrameScript(
+ "data:,(" + runTest.toString() + ")();",
+ false
+ );
+
+ let received = false;
+ let testResult = new Promise(resolve => {
+ let mm = tab.linkedBrowser.messageManager;
+ mm.addMessageListener(
+ "Test:BeforeInputInContentEditable",
+ function onFinish(aMsg) {
+ mm.removeMessageListener(
+ "Test:BeforeInputInContentEditable",
+ onFinish
+ );
+ is(aMsg.data.succeeded, true, aMsg.data.message);
+ resolve();
+ }
+ );
+ });
+ info("Sending Ctrl+K...");
+ await BrowserTestUtils.synthesizeKey(
+ "k",
+ { ctrlKey: true },
+ tab.linkedBrowser
+ );
+ info("Waiting test result...");
+ await testResult;
+ } finally {
+ BrowserTestUtils.removeTab(tab);
+ await extension.unload();
+ }
+});
diff --git a/dom/events/test/browser_bug1539497.js b/dom/events/test/browser_bug1539497.js
new file mode 100644
index 0000000000..e52ec100e3
--- /dev/null
+++ b/dom/events/test/browser_bug1539497.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function maxTouchPoints() {
+ await new Promise(resolve => {
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [
+ ["dom.w3c_pointer_events.enabled", true],
+ ["dom.maxtouchpoints.testing.value", 5],
+ ],
+ },
+ resolve
+ );
+ });
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "data:text/html,Test page for navigator.maxTouchPoints"
+ );
+ await SpecialPowers.spawn(tab.linkedBrowser, [], function() {
+ is(content.navigator.maxTouchPoints, 5, "Should have touch points.");
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/dom/events/test/browser_mouse_enterleave_switch_tab.js b/dom/events/test/browser_mouse_enterleave_switch_tab.js
new file mode 100644
index 0000000000..91f127f34c
--- /dev/null
+++ b/dom/events/test/browser_mouse_enterleave_switch_tab.js
@@ -0,0 +1,158 @@
+"use strict";
+
+async function synthesizeMouseAndWait(aBrowser, aEvent) {
+ let promise = SpecialPowers.spawn(aBrowser, [aEvent], async event => {
+ await new Promise(resolve => {
+ content.document.documentElement.addEventListener(event, resolve, {
+ once: true,
+ });
+ });
+ });
+ // Ensure content has been added event listener.
+ await SpecialPowers.spawn(aBrowser, [], () => {});
+ EventUtils.synthesizeMouse(aBrowser, 10, 10, { type: aEvent });
+ return promise;
+}
+
+function AddMouseEventListener(aBrowser) {
+ return SpecialPowers.spawn(aBrowser, [], () => {
+ content.catchedEvents = [];
+ let listener = function(aEvent) {
+ content.catchedEvents.push(aEvent.type);
+ };
+
+ let target = content.document.querySelector("p");
+ target.onmouseenter = listener;
+ target.onmouseleave = listener;
+ });
+}
+
+function clearMouseEventListenerAndCheck(aBrowser, aExpectedEvents) {
+ return SpecialPowers.spawn(aBrowser, [aExpectedEvents], events => {
+ let target = content.document.querySelector("p");
+ target.onmouseenter = null;
+ target.onmouseleave = null;
+
+ Assert.deepEqual(content.catchedEvents, events);
+ });
+}
+
+add_task(async function testSwitchTabs() {
+ const tabFirst = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "http://example.com/browser/browser/base/content/test/general/dummy_page.html",
+ true
+ );
+
+ info("Initial mouse move");
+ await EventUtils.synthesizeAndWaitNativeMouseMove(
+ tabFirst.linkedBrowser,
+ 10,
+ 10
+ );
+
+ info("Open and move to a new tab");
+ await AddMouseEventListener(tabFirst.linkedBrowser);
+ const tabSecond = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "http://example.com/browser/browser/base/content/test/general/dummy_page.html"
+ );
+ // Synthesize a mousemove to generate corresponding mouseenter and mouseleave
+ // events.
+ await EventUtils.synthesizeAndWaitNativeMouseMove(
+ tabSecond.linkedBrowser,
+ 10,
+ 10
+ );
+ // Wait a bit to see if there is any unexpected mouse event.
+ await TestUtils.waitForTick();
+ await clearMouseEventListenerAndCheck(tabFirst.linkedBrowser, ["mouseleave"]);
+
+ info("switch back to the previous tab");
+ await AddMouseEventListener(tabFirst.linkedBrowser);
+ await AddMouseEventListener(tabSecond.linkedBrowser);
+ await BrowserTestUtils.switchTab(gBrowser, tabFirst);
+ // Synthesize a mousemove to generate corresponding mouseenter and mouseleave
+ // events.
+ await EventUtils.synthesizeAndWaitNativeMouseMove(
+ tabFirst.linkedBrowser,
+ 10,
+ 10
+ );
+ // Wait a bit to see if there is any unexpected mouse event.
+ await TestUtils.waitForTick();
+ await clearMouseEventListenerAndCheck(tabFirst.linkedBrowser, ["mouseenter"]);
+ await clearMouseEventListenerAndCheck(tabSecond.linkedBrowser, [
+ "mouseleave",
+ ]);
+
+ info("Close tabs");
+ BrowserTestUtils.removeTab(tabFirst);
+ BrowserTestUtils.removeTab(tabSecond);
+});
+
+add_task(async function testSwitchTabsWithMouseDown() {
+ const tabFirst = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "http://example.com/browser/browser/base/content/test/general/dummy_page.html",
+ true
+ );
+
+ info("Initial mouse move");
+ await EventUtils.synthesizeAndWaitNativeMouseMove(
+ tabFirst.linkedBrowser,
+ 10,
+ 10
+ );
+
+ info("mouse down");
+ await synthesizeMouseAndWait(tabFirst.linkedBrowser, "mousedown");
+
+ info("Open and move to a new tab");
+ await AddMouseEventListener(tabFirst.linkedBrowser);
+ const tabSecond = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "http://example.com/browser/browser/base/content/test/general/dummy_page.html"
+ );
+ // Synthesize a mousemove to generate corresponding mouseenter and mouseleave
+ // events.
+ await EventUtils.synthesizeAndWaitNativeMouseMove(
+ tabSecond.linkedBrowser,
+ 10,
+ 10
+ );
+
+ info("mouse up");
+ await synthesizeMouseAndWait(tabSecond.linkedBrowser, "mouseup");
+ // Wait a bit to see if there is any unexpected mouse event.
+ await TestUtils.waitForTick();
+ await clearMouseEventListenerAndCheck(tabFirst.linkedBrowser, ["mouseleave"]);
+
+ info("mouse down");
+ await synthesizeMouseAndWait(tabSecond.linkedBrowser, "mousedown");
+
+ info("switch back to the previous tab");
+ await AddMouseEventListener(tabFirst.linkedBrowser);
+ await AddMouseEventListener(tabSecond.linkedBrowser);
+ await BrowserTestUtils.switchTab(gBrowser, tabFirst);
+ // Synthesize a mousemove to generate corresponding mouseenter and mouseleave
+ // events.
+ await EventUtils.synthesizeAndWaitNativeMouseMove(
+ tabFirst.linkedBrowser,
+ 10,
+ 10
+ );
+
+ info("mouse up");
+ await synthesizeMouseAndWait(tabFirst.linkedBrowser, "mouseup");
+ // Wait a bit to see if there is any unexpected mouse event.
+ await TestUtils.waitForTick();
+ await clearMouseEventListenerAndCheck(tabFirst.linkedBrowser, ["mouseenter"]);
+ await clearMouseEventListenerAndCheck(tabSecond.linkedBrowser, [
+ "mouseleave",
+ ]);
+
+ info("Close tabs");
+ BrowserTestUtils.removeTab(tabFirst);
+ BrowserTestUtils.removeTab(tabSecond);
+});
diff --git a/dom/events/test/browser_shortcutkey_modifier_conflicts_with_content_accesskey_modifier.js b/dom/events/test/browser_shortcutkey_modifier_conflicts_with_content_accesskey_modifier.js
new file mode 100644
index 0000000000..67fa3c36eb
--- /dev/null
+++ b/dom/events/test/browser_shortcutkey_modifier_conflicts_with_content_accesskey_modifier.js
@@ -0,0 +1,102 @@
+add_task(async function() {
+ // Even if modifier of a shortcut key same as modifier of content access key,
+ // the shortcut key should be executed if (remote) content doesn't handle it.
+ // This test uses existing shortcut key declaration on Linux and Windows.
+ // If you remove or change Alt + D, you need to keep check this with changing
+ // the pref or result check.
+
+ await new Promise(resolve => {
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [
+ ["ui.key.generalAccessKey", -1],
+ ["ui.key.chromeAccess", 0 /* disabled */],
+ ["ui.key.contentAccess", 4 /* Alt */],
+ ["browser.search.widget.inNavBar", true],
+ ],
+ },
+ resolve
+ );
+ });
+
+ const kTestPage = "data:text/html,<body>simple web page</body>";
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kTestPage);
+
+ let searchBar = BrowserSearch.searchBar;
+ searchBar.focus();
+
+ function promiseURLBarHasFocus() {
+ return new Promise(resolve => {
+ if (gURLBar.focused) {
+ ok(true, "The URL bar already has focus");
+ resolve();
+ return;
+ }
+ info("Waiting focus event...");
+ gURLBar.addEventListener(
+ "focus",
+ () => {
+ ok(true, "The URL bar gets focus");
+ resolve();
+ },
+ { once: true }
+ );
+ });
+ }
+
+ function promiseURLBarSelectsAllText() {
+ return new Promise(resolve => {
+ function isAllTextSelected() {
+ return (
+ gURLBar.inputField.selectionStart === 0 &&
+ gURLBar.inputField.selectionEnd === gURLBar.inputField.value.length
+ );
+ }
+ if (isAllTextSelected()) {
+ ok(true, "All text of the URL bar is already selected");
+ isnot(
+ gURLBar.inputField.value,
+ "",
+ "The URL bar should have non-empty text"
+ );
+ resolve();
+ return;
+ }
+ info("Waiting selection changes...");
+ function tryToCheckItLater() {
+ if (!isAllTextSelected()) {
+ SimpleTest.executeSoon(tryToCheckItLater);
+ return;
+ }
+ ok(true, "All text of the URL bar should be selected");
+ isnot(
+ gURLBar.inputField.value,
+ "",
+ "The URL bar should have non-empty text"
+ );
+ resolve();
+ }
+ SimpleTest.executeSoon(tryToCheckItLater);
+ });
+ }
+
+ // Alt + D is a shortcut key to move focus to the URL bar and selects its text.
+ info("Pressing Alt + D in the search bar...");
+ EventUtils.synthesizeKey("d", { altKey: true });
+
+ await promiseURLBarHasFocus();
+ await promiseURLBarSelectsAllText();
+
+ // Alt + D in the URL bar should select all text in it.
+ await gURLBar.focus();
+ await promiseURLBarHasFocus();
+ gURLBar.inputField.selectionStart = gURLBar.inputField.selectionEnd =
+ gURLBar.inputField.value.length;
+
+ info("Pressing Alt + D in the URL bar...");
+ EventUtils.synthesizeKey("d", { altKey: true });
+ await promiseURLBarHasFocus();
+ await promiseURLBarSelectsAllText();
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/dom/events/test/bug1017086_inner.html b/dom/events/test/bug1017086_inner.html
new file mode 100644
index 0000000000..10e7f4d555
--- /dev/null
+++ b/dom/events/test/bug1017086_inner.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1017086
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1017086</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ /** Test for Bug 1017086 **/
+ var testelem = undefined;
+ var pointer_events = ["onpointerover", "onpointerenter",
+ "onpointermove",
+ "onpointerdown", "onpointerup",
+ "onpointerout", "onpointerleave",
+ "onpointercancel"];
+ function check(expected_value, event_name, container, container_name) {
+ var text = event_name + " in " + container_name + " should be " + expected_value;
+ parent.is(event_name in container, expected_value, text);
+ }
+ function runTest() {
+ testelem = document.getElementById("test");
+ is(!!testelem, true, "Document should have element with id 'test'");
+ parent.turnOnOffPointerEvents( function() {
+ parent.part_of_checks(pointer_events, check, window, document, testelem);
+ });
+ }
+ </script>
+</head>
+<body onload="runTest();">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1017086">Mozilla Bug 1017086</a>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+</body>
+</html>
diff --git a/dom/events/test/bug226361_iframe.xhtml b/dom/events/test/bug226361_iframe.xhtml
new file mode 100644
index 0000000000..df38a8bcbe
--- /dev/null
+++ b/dom/events/test/bug226361_iframe.xhtml
@@ -0,0 +1,47 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=226361
+-->
+<head>
+ <title>Test for Bug 226361</title>
+</head>
+<body id="body">
+<p id="display">
+
+<a id="a1" tabindex="3" href="http://home.mozilla.org">This is the 1st
+
+link but the 3rd tabindex</a><br />
+
+<br />
+
+ <a id="a2" tabindex="4" href="http://home.mozilla.org">This is the 2nd
+
+link but the 4th tabindex</a><br />
+
+<br />
+
+ <a id="a3" tabindex="1" href="http://home.mozilla.org">This is the 3rd
+
+link but the 1st tabindex</a><br />
+
+<br />
+
+ <a id="a4" tabindex="5" href="http://home.mozilla.org">This is the 4th
+
+link but the 5th tabindex</a><br />
+
+<br />
+
+ <a id="a5" tabindex="2" href="http://home.mozilla.org">This is the 5th
+
+link but the 2nd tabindex</a>
+
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/bug299673.js b/dom/events/test/bug299673.js
new file mode 100644
index 0000000000..07e33bd137
--- /dev/null
+++ b/dom/events/test/bug299673.js
@@ -0,0 +1,150 @@
+var popup;
+
+function OpenWindow() {
+ log({}, ">>> OpenWindow");
+ popup = window.open("", "Test");
+
+ var output = "<html>";
+
+ output += "<body>";
+ output += "<form>";
+ output +=
+ "<input id='popupText1' type='text' onfocus='opener.log(event)' onblur='opener.log(event)'>";
+ output += "</form>";
+ output += "</body>";
+ output += "</html>";
+
+ popup.document.open();
+ popup.document.write(output);
+ popup.document.close();
+
+ popup.document.onclick = function(event) {
+ log(event, "popup-doc");
+ };
+ popup.document.onfocus = function(event) {
+ log(event, "popup-doc");
+ };
+ popup.document.onblur = function(event) {
+ log(event, "popup-doc");
+ };
+ popup.document.onchange = function(event) {
+ log(event, "popup-doc");
+ };
+
+ var e = popup.document.getElementById("popupText1");
+ popup.focus();
+ e.focus();
+ is(
+ popup.document.activeElement,
+ e,
+ "input element in popup should be focused"
+ );
+ log({}, "<<< OpenWindow");
+}
+
+var result;
+
+function log(event, message) {
+ if (event && event.eventPhase == 3) {
+ return;
+ }
+ e = event.currentTarget || event.target || event.srcElement;
+ var id = e ? (e.id ? e.id : e.name ? e.name : e.value ? e.value : "") : "";
+ if (id) {
+ id = "(" + id + ")";
+ }
+ result +=
+ (e ? (e.tagName ? e.tagName : "") : " ") +
+ id +
+ ": " +
+ (event.type ? event.type : "") +
+ " " +
+ (message ? message : "") +
+ "\n";
+}
+
+document.onclick = function(event) {
+ log(event, "top-doc");
+};
+document.onfocus = function(event) {
+ log(event, "top-doc");
+};
+document.onblur = function(event) {
+ log(event, "top-doc");
+};
+document.onchange = function(event) {
+ log(event, "top-doc");
+};
+
+function doTest1_rest2(expectedEventLog, focusAfterCloseId) {
+ try {
+ is(
+ document.activeElement,
+ document.getElementById(focusAfterCloseId),
+ "wrong element is focused after popup was closed"
+ );
+ is(result, expectedEventLog, "unexpected events");
+ SimpleTest.finish();
+ } catch (e) {
+ if (popup) {
+ popup.close();
+ }
+ throw e;
+ }
+}
+function doTest1_rest1(expectedEventLog, focusAfterCloseId) {
+ try {
+ synthesizeKey("V", {}, popup);
+ synthesizeKey("A", {}, popup);
+ synthesizeKey("L", {}, popup);
+ is(
+ popup.document.getElementById("popupText1").value,
+ "VAL",
+ "input element in popup did not accept input"
+ );
+
+ var p = popup;
+ popup = null;
+ p.close();
+
+ SimpleTest.waitForFocus(function() {
+ doTest1_rest2(expectedEventLog, focusAfterCloseId);
+ }, window);
+ } catch (e) {
+ if (popup) {
+ popup.close();
+ }
+ throw e;
+ }
+}
+
+function doTest1(expectedEventLog, focusAfterCloseId) {
+ try {
+ var select1 = document.getElementById("Select1");
+ select1.focus();
+ is(document.activeElement, select1, "select element should be focused");
+ synthesizeKey("KEY_ArrowDown");
+ synthesizeKey("KEY_Tab");
+ SimpleTest.waitForFocus(function() {
+ doTest1_rest1(expectedEventLog, focusAfterCloseId);
+ }, popup);
+ } catch (e) {
+ if (popup) {
+ popup.close();
+ }
+ throw e;
+ }
+}
+
+function setPrefAndDoTest(expectedEventLog, focusAfterCloseId, prefValue) {
+ var select1 = document.getElementById("Select1");
+ select1.blur();
+ result = "";
+ log({}, "Test with browser.link.open_newwindow = " + prefValue);
+ SpecialPowers.pushPrefEnv(
+ { set: [["browser.link.open_newwindow", prefValue]] },
+ function() {
+ doTest1(expectedEventLog, focusAfterCloseId);
+ }
+ );
+}
diff --git a/dom/events/test/bug322588-popup.html b/dom/events/test/bug322588-popup.html
new file mode 100644
index 0000000000..767eb9db9c
--- /dev/null
+++ b/dom/events/test/bug322588-popup.html
@@ -0,0 +1 @@
+<html><head></head><body onblur="window.close()"><a id="target">a id=target</a></body></html>
diff --git a/dom/events/test/bug415498-doc1.html b/dom/events/test/bug415498-doc1.html
new file mode 100644
index 0000000000..e8fbca6c9a
--- /dev/null
+++ b/dom/events/test/bug415498-doc1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script type="text/javascript">
+function init() {
+ // This will throw a HierarchyRequestError exception
+ var doc = document.implementation.createDocument(null, 'DOC', null);
+ doc.documentElement.appendChild(doc);
+}
+window.addEventListener("load", init);
+</script>
+</head>
+<body>
+ Testcase for bug 415498. This page should show an exception in Error Console on load
+</body>
diff --git a/dom/events/test/bug415498-doc2.html b/dom/events/test/bug415498-doc2.html
new file mode 100644
index 0000000000..e556a4e4ca
--- /dev/null
+++ b/dom/events/test/bug415498-doc2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script type="text/javascript">
+function init() {
+ // This will throw a HierarchyRequestError exception
+ var doc = document.implementation.createDocument(null, 'DOC', null);
+ doc.documentElement.appendChild(doc);
+}
+onload = init;
+</script>
+</head>
+<body>
+ Testcase for bug 415498. This page should show an exception in Error Console on load
+</body>
diff --git a/dom/events/test/bug418986-3.js b/dom/events/test/bug418986-3.js
new file mode 100644
index 0000000000..cc3687c0d0
--- /dev/null
+++ b/dom/events/test/bug418986-3.js
@@ -0,0 +1,83 @@
+SimpleTest.waitForExplicitFinish();
+
+// The main testing function.
+var test = function(isContent) {
+ // Each definition is [eventType, prefSetting]
+ // Where we are setting the "privacy.resistFingerprinting" pref.
+ let eventDefs = [
+ ["mousedown", true],
+ ["mouseup", true],
+ ["mousedown", false],
+ ["mouseup", false],
+ ];
+
+ let testCounter = 0;
+
+ // Declare ahead of time.
+ let setup;
+
+ // This function is called when the event handler fires.
+ let handleEvent = function(event, prefVal) {
+ let resisting = prefVal && isContent;
+ if (resisting) {
+ is(
+ event.screenX,
+ event.clientX,
+ "event.screenX and event.clientX should be the same"
+ );
+ is(
+ event.screenY,
+ event.clientY,
+ "event.screenY and event.clientY should be the same"
+ );
+ } else {
+ // We can't be sure about X coordinates not being equal, but we can test Y.
+ isnot(event.screenY, event.clientY, "event.screenY !== event.clientY");
+ }
+ ++testCounter;
+ if (testCounter < eventDefs.length) {
+ nextTest();
+ } else {
+ SimpleTest.finish();
+ }
+ };
+
+ // In this function, we set up the nth div and event handler,
+ // and then synthesize a mouse event in the div, to test
+ // whether the resulting events resist fingerprinting by
+ // suppressing absolute screen coordinates.
+ nextTest = function() {
+ let [eventType, prefVal] = eventDefs[testCounter];
+ SpecialPowers.pushPrefEnv(
+ { set: [["privacy.resistFingerprinting", prefVal]] },
+ function() {
+ // The following code creates a new div for each event in eventDefs,
+ // attaches a listener to listen for the event, and then generates
+ // a fake event at the center of the div.
+ let div = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "div"
+ );
+ div.style.width = "10px";
+ div.style.height = "10px";
+ div.style.backgroundColor = "red";
+ // Name the div after the event we're listening for.
+ div.id = eventType;
+ document.getElementById("body").appendChild(div);
+ // Seems we can't add an event listener in chrome unless we run
+ // it in a later task.
+ window.setTimeout(function() {
+ div.addEventListener(eventType, event => handleEvent(event, prefVal));
+ // For some reason, the following synthesizeMouseAtCenter call only seems to run if we
+ // wrap it in a window.setTimeout(..., 0).
+ window.setTimeout(function() {
+ synthesizeMouseAtCenter(div, { type: eventType });
+ }, 0);
+ }, 0);
+ }
+ );
+ };
+
+ // Now run by starting with the 0th event.
+ nextTest();
+};
diff --git a/dom/events/test/bug426082.html b/dom/events/test/bug426082.html
new file mode 100644
index 0000000000..b8bf5cb243
--- /dev/null
+++ b/dom/events/test/bug426082.html
@@ -0,0 +1,116 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=426082
+-->
+<head>
+ <title>Test for Bug 426082</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=426082">Mozilla Bug 426082</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<p><input type="button" value="Button" id="button"></p>
+<p><label for="button" id="label">Label</label></p>
+<p id="outside">Something under the label</p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 426082 **/
+
+function runTests() {
+ SimpleTest.executeSoon(tests);
+}
+
+SimpleTest.waitForFocus(runTests);
+
+function oneTick() {
+ return new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
+}
+
+function sendMouseEvent(t, elem) {
+ let r = elem.getBoundingClientRect();
+ synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
+}
+
+async function tests() {
+ let button = document.getElementById("button");
+ let label = document.getElementById("label");
+ let outside = document.getElementById("outside");
+
+ let is = window.opener.is;
+ let ok = window.opener.ok;
+
+ // Press the label.
+ sendMouseEvent("mousemove", label);
+ sendMouseEvent("mousedown", label);
+
+ await oneTick();
+
+ ok(label.matches(":hover"), "Label is hovered");
+ ok(button.matches(":hover"), "Button should be hovered too");
+
+ ok(label.matches(":active"), "Label is active");
+ ok(button.matches(":active"), "Button should be active too");
+
+ // Move the mouse down from the label.
+ sendMouseEvent("mousemove", outside);
+
+ await oneTick();
+
+ ok(!label.matches(":hover"), "Label is no longer hovered");
+ ok(!button.matches(":hover"), "Button should not be hovered too");
+
+ ok(label.matches(":active"), "Label is still active");
+ ok(button.matches(":active"), "Button is still active too");
+
+ // And up again.
+ sendMouseEvent("mousemove", label);
+
+ await oneTick();
+
+
+ ok(label.matches(":hover"), "Label hovered again");
+ ok(button.matches(":hover"), "Button be hovered again");
+ ok(label.matches(":active"), "Label is still active");
+ ok(button.matches(":active"), "Button is still active too");
+
+ // Release.
+ sendMouseEvent("mouseup", label);
+
+ await oneTick();
+
+ ok(!label.matches(":active"), "Label is no longer active");
+ ok(!button.matches(":active"), "Button is no longer active");
+
+ ok(label.matches(":hover"), "Label is still hovered");
+ ok(button.matches(":hover"), "Button is still hovered");
+
+ // Press the label and remove it.
+ sendMouseEvent("mousemove", label);
+ sendMouseEvent("mousedown", label);
+
+ await oneTick();
+
+ label.remove();
+
+ await oneTick();
+
+ ok(!label.matches(":active"), "Removing label should have unpressed it");
+ ok(!label.matches(":focus"), "Removing label should have unpressed it");
+ ok(!label.matches(":hover"), "Removing label should have unhovered it");
+ ok(!button.matches(":active"), "Removing label should have unpressed the button");
+ ok(!button.matches(":focus"), "Removing label should have unpressed the button");
+ ok(!button.matches(":hover"), "Removing label should have unhovered the button");
+
+ sendMouseEvent("mouseup", label);
+ window.opener.finishTests();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/bug545268.html b/dom/events/test/bug545268.html
new file mode 100644
index 0000000000..1f90149a54
--- /dev/null
+++ b/dom/events/test/bug545268.html
@@ -0,0 +1 @@
+<iframe id='f' style='position:absolute; border:none; width:100%; height:100%; left:0; top:0' srcdoc='<input>'>
diff --git a/dom/events/test/bug574663.html b/dom/events/test/bug574663.html
new file mode 100644
index 0000000000..a3a5bd30ba
--- /dev/null
+++ b/dom/events/test/bug574663.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div id="scrollbox" style="height: 100px; overflow: auto;">
+<div style="height: 1000px;"></div></div>
diff --git a/dom/events/test/bug591249_iframe.xhtml b/dom/events/test/bug591249_iframe.xhtml
new file mode 100644
index 0000000000..7c7d7642b1
--- /dev/null
+++ b/dom/events/test/bug591249_iframe.xhtml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=591249
+-->
+<window title="Mozilla Bug 591249"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <html:style type="text/css">
+ #drop-target {
+ width: 50px;
+ height: 50px;
+ border: 4px dotted black;
+ }
+ #drop-target {
+ background-color: red;
+ }
+ #drop-target:-moz-drag-over {
+ background-color: yellow;
+ }
+ </html:style>
+
+ <html:body>
+ <html:h1 id="iframetext">Iframe for Bug 591249</html:h1>
+
+ <html:div id="drop-target"
+ ondrop="return false;"
+ ondragenter="return false;"
+ ondragover="return false;">
+ </html:div>
+ </html:body>
+</window>
diff --git a/dom/events/test/bug602962.xhtml b/dom/events/test/bug602962.xhtml
new file mode 100644
index 0000000000..0d54b7ad52
--- /dev/null
+++ b/dom/events/test/bug602962.xhtml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window onload="window.opener.doTest()" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <scrollbox id="page-scrollbox" style="border: 1px solid red; background-color: black;overflow: auto" flex="1">
+ <box id="page-box" style="border: 1px solid green;"/>
+ </scrollbox>
+</window>
diff --git a/dom/events/test/bug607464.html b/dom/events/test/bug607464.html
new file mode 100644
index 0000000000..55d1152623
--- /dev/null
+++ b/dom/events/test/bug607464.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div id="scrollbox" style="height: 100px; overflow: auto;">
+<div style="height: 1000px;"></div> </div>
diff --git a/dom/events/test/bug656379-1.html b/dom/events/test/bug656379-1.html
new file mode 100644
index 0000000000..bfff2e2cd0
--- /dev/null
+++ b/dom/events/test/bug656379-1.html
@@ -0,0 +1,186 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=656379
+-->
+<head>
+ <title>Test for Bug 656379</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ canvas {
+ display: none;
+ }
+ input[type=button] {
+ appearance: none;
+ padding: 0;
+ border: none;
+ color: black;
+ background: white;
+ }
+ input[type=button]::-moz-focus-inner { border: none; }
+
+ /* Make sure that normal, focused, hover+active, focused+hover+active
+ buttons all have different styles so that the test keeps moving along. */
+ input[type=button]:hover:active {
+ background: red;
+ }
+ input[type=button]:focus {
+ background: green;
+ }
+ input[type=button]:focus:hover:active {
+ background: purple;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=656379">Mozilla Bug 656379</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+
+var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
+ pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
+
+function runTests() {
+ button = $("button");
+ label = $("label");
+ outside = $("outside");
+ SimpleTest.executeSoon(executeTests);
+}
+
+SimpleTest.waitForFocus(runTests);
+
+function isRectContainedInRectFromRegion(rect, region) {
+ return Array.prototype.some.call(region, function (r) {
+ return rect.left >= r.left &&
+ rect.top >= r.top &&
+ rect.right <= r.right &&
+ rect.bottom <= r.bottom;
+ });
+}
+
+function paintListener(e) {
+ if (isRectContainedInRectFromRegion(buttonRect(), SpecialPowers.wrap(e).clientRects)) {
+ gNeedsPaint = false;
+ currentSnapshot = takeSnapshot();
+ }
+}
+
+var gNeedsPaint = false;
+function executeTests() {
+ var testYielder = tests();
+ function execNext() {
+ if (!gNeedsPaint) {
+ let {done} = testYielder.next();
+ if (done) {
+ return;
+ }
+ button.getBoundingClientRect(); // Flush.
+ gNeedsPaint = true;
+ }
+ SimpleTest.executeSoon(execNext);
+ }
+ execNext();
+}
+
+function* tests() {
+ window.addEventListener("MozAfterPaint", paintListener);
+ normalButtonCanvas = takeSnapshot();
+ // Press the button.
+ sendMouseEvent("mousemove", button);
+ sendMouseEvent("mousedown", button);
+ yield undefined;
+ pressedFocusedButtonCanvas = takeSnapshot();
+ compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
+ // Release.
+ sendMouseEvent("mouseup", button);
+ yield undefined;
+ // make sure the button is focused as this doesn't happen on click on Mac
+ button.focus();
+ normalFocusedButtonCanvas = takeSnapshot();
+ compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
+ // Unfocus the button.
+ sendMouseEvent("mousedown", outside);
+ sendMouseEvent("mouseup", outside);
+ yield undefined;
+
+ // Press the label.
+ sendMouseEvent("mousemove", label);
+ sendMouseEvent("mousedown", label);
+ yield undefined;
+ compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
+ pressedButtonCanvas = takeSnapshot();
+ // Move the mouse down from the label.
+ sendMouseEvent("mousemove", outside);
+ yield undefined;
+ compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
+ // ... and up again.
+ sendMouseEvent("mousemove", label);
+ yield undefined;
+ compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
+ // Release.
+ sendMouseEvent("mouseup", label);
+ yield undefined;
+ var focusOnMouse = (navigator.platform.indexOf("Mac") != 0);
+ compareSnapshots_(focusOnMouse ? normalFocusedButtonCanvas : normalButtonCanvas,
+ currentSnapshot, true, "Releasing the mouse over the label should have unpressed" +
+ (focusOnMouse ? " (and focused)" : "") + " the button.");
+ // Press the label and remove it.
+ sendMouseEvent("mousemove", label);
+ sendMouseEvent("mousedown", label);
+ yield undefined;
+ label.remove();
+ yield undefined;
+ compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
+ sendMouseEvent("mouseup", label);
+ window.removeEventListener("MozAfterPaint", paintListener);
+ window.opener.finishTests();
+ }
+
+function sendMouseEvent(t, elem) {
+ var r = elem.getBoundingClientRect();
+ synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
+}
+
+function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
+ var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
+ if (correct) {
+ if (shouldBeIdentical) {
+ window.opener.ok(true, msg + " - expected " + c1url);
+ } else {
+ window.opener.ok(true, msg + " - got " + c1url + " and " + c2url);
+ }
+ } else {
+ if (shouldBeIdentical) {
+ window.opener.ok(false, msg + " - expected " + c1url + " but got " + c2url);
+ } else {
+ window.opener.ok(false, msg + " - expected something other than " + c1url);
+ }
+ }
+}
+
+function takeSnapshot(canvas) {
+ var r = buttonRect();
+ adjustedRect = { left: r.left - 2, top: r.top - 2,
+ width: r.width + 4, height: r.height + 4 };
+ return SpecialPowers.snapshotRect(window, adjustedRect);
+}
+
+function buttonRect() {
+ return button.getBoundingClientRect();
+}
+</script>
+</pre>
+<p><input type="button" value="Button" id="button"></p>
+<p><label for="button" id="label">Label</label></p>
+<p id="outside">Something under the label</p>
+
+</body>
+</html>
diff --git a/dom/events/test/chrome.ini b/dom/events/test/chrome.ini
new file mode 100644
index 0000000000..e14d8b65a2
--- /dev/null
+++ b/dom/events/test/chrome.ini
@@ -0,0 +1,30 @@
+[DEFAULT]
+skip-if = os == 'android'
+support-files =
+ bug415498-doc1.html
+ bug415498-doc2.html
+ bug418986-3.js
+ bug591249_iframe.xhtml
+ bug602962.xhtml
+ file_bug679494.html
+ window_bug617528.xhtml
+ window_bug1412775.xhtml
+ test_bug336682.js
+
+[test_bug336682_2.xhtml]
+[test_bug415498.xhtml]
+[test_bug418986-3.xhtml]
+[test_bug524674.xhtml]
+[test_bug586961.xhtml]
+[test_bug591249.xhtml]
+[test_bug602962.xhtml]
+[test_bug617528.xhtml]
+[test_bug679494.xhtml]
+[test_bug930374-chrome.html]
+[test_bug1128787-1.html]
+[test_bug1128787-2.html]
+[test_bug1128787-3.html]
+[test_bug1412775.xhtml]
+[test_eventctors.xhtml]
+[test_DataTransferItemList.html]
+skip-if = !debug && (os == "linux") #Bug 1421150
diff --git a/dom/events/test/empty.js b/dom/events/test/empty.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/events/test/empty.js
diff --git a/dom/events/test/error_event_worker.js b/dom/events/test/error_event_worker.js
new file mode 100644
index 0000000000..f637d05ddc
--- /dev/null
+++ b/dom/events/test/error_event_worker.js
@@ -0,0 +1,19 @@
+addEventListener("error", function(e) {
+ var obj = {};
+ for (var prop of ["message", "filename", "lineno"]) {
+ obj[prop] = e[prop];
+ }
+ obj.type = "event";
+ postMessage(obj);
+});
+onerror = function(message, filename, lineno) {
+ var obj = {
+ message,
+ filename,
+ lineno,
+ type: "callback",
+ };
+ postMessage(obj);
+ return false;
+};
+throw new Error("workerhello");
diff --git a/dom/events/test/event_leak_utils.js b/dom/events/test/event_leak_utils.js
new file mode 100644
index 0000000000..86b26a4136
--- /dev/null
+++ b/dom/events/test/event_leak_utils.js
@@ -0,0 +1,84 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// This function runs a number of tests where:
+//
+// 1. An iframe is created
+// 2. The target callback is executed with the iframe's contentWindow as
+// an argument.
+// 3. The iframe is destroyed and GC is forced.
+// 4. Verifies that the iframe's contentWindow has been GC'd.
+//
+// Different ways of destroying the iframe are checked. Simple
+// remove(), destruction via bfcache, or replacement by document.open().
+//
+// Please pass a target callback that exercises the API under
+// test using the given window. The callback should try to leave the
+// API active to increase the liklihood of provoking an API. Any activity
+// should be canceled by the destruction of the window.
+async function checkForEventListenerLeaks(name, target) {
+ // Test if we leak in the case where we do nothing special to
+ // the frame before removing it from the DOM.
+ await _eventListenerLeakStep(target, `${name} default`);
+
+ // Test the case where we navigate the frame before removing it
+ // from the DOM so that the window using the target API ends up
+ // in bfcache.
+ await _eventListenerLeakStep(target, `${name} bfcache`, frame => {
+ frame.src = "about:blank";
+ return new Promise(resolve => (frame.onload = resolve));
+ });
+
+ // Test the case where we document.open() the frame before removing
+ // it from the DOM so that the window using the target API ends
+ // up getting replaced.
+ await _eventListenerLeakStep(target, `${name} document.open()`, frame => {
+ frame.contentDocument.open();
+ frame.contentDocument.close();
+ });
+}
+
+// ----------------
+// Internal helpers
+// ----------------
+
+// Utility function to create a loaded iframe.
+async function _withFrame(doc, url) {
+ let frame = doc.createElement("iframe");
+ frame.src = url;
+ doc.body.appendChild(frame);
+ await new Promise(resolve => (frame.onload = resolve));
+ return frame;
+}
+
+// This function defines the basic form of the test cases. We create an
+// iframe, execute the target callback to manipulate the DOM, remove the frame
+// from the DOM, and then check to see if the frame was GC'd. The caller
+// may optionally pass in a callback that will be executed with the
+// frame as an argument before removing it from the DOM.
+async function _eventListenerLeakStep(target, name, extra) {
+ let frame = await _withFrame(document, "empty.html");
+
+ await target(frame.contentWindow);
+
+ let weakRef = SpecialPowers.Cu.getWeakReference(frame.contentWindow);
+ ok(weakRef.get(), `should be able to create a weak reference - ${name}`);
+
+ if (extra) {
+ await extra(frame);
+ }
+
+ frame.remove();
+ frame = null;
+
+ // Perform many GC's to avoid intermittent delayed collection.
+ await new Promise(resolve => SpecialPowers.exactGC(resolve));
+ await new Promise(resolve => SpecialPowers.exactGC(resolve));
+ await new Promise(resolve => SpecialPowers.exactGC(resolve));
+
+ ok(
+ !weakRef.get(),
+ `iframe content window should be garbage collected - ${name}`
+ );
+}
diff --git a/dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html b/dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html
new file mode 100644
index 0000000000..722b101a3b
--- /dev/null
+++ b/dom/events/test/file_beforeinput_by_execCommand_in_contentscript.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<div contenteditable>abcdef</div>
diff --git a/dom/events/test/file_bug1446834.html b/dom/events/test/file_bug1446834.html
new file mode 100644
index 0000000000..e3832fd2f0
--- /dev/null
+++ b/dom/events/test/file_bug1446834.html
@@ -0,0 +1,96 @@
+<html>
+ <head>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script>
+
+ function lazyRequestAnimationFrame(fn) {
+ requestAnimationFrame(
+ function() {
+ setTimeout(fn);
+ });
+ }
+
+ var tests = [ removeHost, removeShadowElement ];
+ function nextTest() {
+ if (tests.length) {
+ var test = tests.shift();
+ lazyRequestAnimationFrame(test);
+ } else {
+ parent.SimpleTest.finish();
+ }
+ }
+
+ function removeHost() {
+ var hostgrandparent = document.getElementById("hostgrandparent");
+ var hostparent = document.getElementById("hostparent");
+ hostparent.innerHTML = "<div id='host'></div>";
+ var host = document.getElementById("host");
+ var sr = document.getElementById("host").attachShadow({mode: "open"});
+ sr.innerHTML = "<input type='button' value='click'>";
+ sr.firstChild.onclick = function() {
+ parent.is(hostparent.querySelector("div:hover"), host, "host should be hovered.");
+ host.remove();
+ parent.is(hostgrandparent.querySelector("div:hover"), hostparent,
+ "hostgrandparent element should have descendants marked in :hover state.");
+ synthesizeMouseAtCenter(document.getElementById('light'), { type: "mousemove" });
+ lazyRequestAnimationFrame(
+ function() {
+ parent.is(hostgrandparent.querySelector("div:hover"), null,
+ "hostgrandparent element shouldn't have descendants marked in :hover state anymore.");
+ nextTest();
+ }
+ );
+ }
+ lazyRequestAnimationFrame(
+ function() {
+ synthesizeMouseAtCenter(sr.firstChild, { type: "mousemove" });
+ synthesizeMouseAtCenter(sr.firstChild, {});
+ }
+ );
+ }
+
+ function removeShadowElement() {
+ var hostgrandparent = document.getElementById("hostgrandparent");
+ var hostparent = document.getElementById("hostparent");
+ hostparent.innerHTML = "<div id='host'><input id='input' slot='slot' type='button' value='click'></div>";
+ var host = document.getElementById("host");
+ var input = document.getElementById("input");
+ var sr = document.getElementById("host").attachShadow({mode: "open"});
+ sr.innerHTML = "<div><div><slot name='slot'></slot></div></div>";
+ var shadowOuterDiv = sr.firstChild;
+ var shadowInnerDiv = shadowOuterDiv.firstChild;
+ var slot = shadowInnerDiv.firstChild;
+ sr.firstChild.onclick = function() {
+ parent.is(hostparent.querySelector("div:hover"), host, "host should be hovered.");
+ slot.remove();
+ parent.is(shadowOuterDiv.querySelector("div:hover"), shadowInnerDiv,
+ "Elements in shadow DOM should stay hovered");
+ synthesizeMouseAtCenter(document.getElementById('light'), { type: "mousemove" });
+ lazyRequestAnimationFrame(
+ function() {
+ parent.is(shadowOuterDiv.querySelector("div:hover"), null,
+ "Shadow DOM shouldn't be marked to be hovered anymore.");
+ nextTest();
+ }
+ );
+ }
+ lazyRequestAnimationFrame(
+ function() {
+ synthesizeMouseAtCenter(input, { type: "mousemove" });
+ synthesizeMouseAtCenter(input, {});
+ }
+ );
+ }
+ </script>
+ <style>
+ </style>
+ </head>
+ <body onload="nextTest()">
+ <div id="hostgrandparent">
+ <div id="hostparent">
+ </div>
+ foo
+ </div>
+ <div id="light">light dom</div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/file_bug1484371.html b/dom/events/test/file_bug1484371.html
new file mode 100644
index 0000000000..56c284b733
--- /dev/null
+++ b/dom/events/test/file_bug1484371.html
@@ -0,0 +1,94 @@
+<html>
+ <head>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script>
+ var mouseEnterCount = 0;
+ function mouseEnter() {
+ ++mouseEnterCount;
+ }
+ var mouseLeaveCount = 0;
+ function mouseLeave() {
+ ++mouseLeaveCount;
+ }
+
+ var pointerEnterCount = 0;
+ function pointerEnter() {
+ ++pointerEnterCount;
+ }
+ var pointerLeaveCount = 0;
+ function pointerLeave() {
+ ++pointerLeaveCount;
+ }
+
+ function pointerEventsEnabled() {
+ return "onpointerenter" in document.body;
+ }
+
+ function checkEventCounts(expected, msg) {
+ parent.is(mouseEnterCount, expected.mouseEnterCount, msg + ": mouseenter event count");
+ parent.is(mouseLeaveCount, expected.mouseLeaveCount, msg + ": mouseleave event count");
+ if (pointerEventsEnabled()) {
+ parent.is(pointerEnterCount, expected.pointerEnterCount, msg + ": pointerenter event count");
+ parent.is(pointerLeaveCount, expected.pointerLeaveCount, msg + ": pointerleave event count");
+ }
+ }
+
+ function test() {
+ var lightDiv = document.getElementById("lightDiv");
+ var host = document.getElementById("host");
+ var sr = host.attachShadow({mode: "closed"});
+ sr.innerHTML = "<div>shadow DOM<div>";
+ var shadowDiv = sr.firstChild;
+
+ host.addEventListener("mouseenter", mouseEnter, true);
+ host.addEventListener("mouseleave", mouseLeave, true);
+ host.addEventListener("pointerenter", pointerEnter, true);
+ host.addEventListener("pointerleave", pointerLeave, true);
+
+ shadowDiv.addEventListener("mouseenter", mouseEnter, true);
+ shadowDiv.addEventListener("mouseleave", mouseLeave, true);
+ shadowDiv.addEventListener("pointerenter", pointerEnter, true);
+ shadowDiv.addEventListener("pointerleave", pointerLeave, true);
+
+ synthesizeMouseAtCenter(lightDiv, { type: "mousemove" });
+ checkEventCounts({ mouseEnterCount: 0,
+ mouseLeaveCount: 0,
+ pointerEnterCount: 0,
+ pointerLeaveCount: 0
+ },
+ "Entered light DOM"
+ );
+
+ synthesizeMouseAtCenter(shadowDiv, { type: "mousemove" })
+ checkEventCounts({ mouseEnterCount: 2,
+ mouseLeaveCount: 0,
+ pointerEnterCount: 2,
+ pointerLeaveCount: 0
+ },
+ "Entered shadow DOM");
+
+ synthesizeMouseAtCenter(lightDiv, { type: "mousemove" })
+ checkEventCounts({ mouseEnterCount: 2,
+ mouseLeaveCount: 2,
+ pointerEnterCount: 2,
+ pointerLeaveCount: 2
+ },
+ "Left shadow DOM"
+ );
+
+ parent.SimpleTest.finish();
+ }
+
+ function lazyRequestAnimationFrame(fn) {
+ requestAnimationFrame(
+ function() {
+ setTimeout(fn);
+ });
+ }
+ </script>
+ </head>
+ <body onload="lazyRequestAnimationFrame(test)">
+ <div id="lightDiv">light DOM</div>
+ <div id="host"></div>
+ </body>
+</html>
diff --git a/dom/events/test/file_bug679494.html b/dom/events/test/file_bug679494.html
new file mode 100644
index 0000000000..a2e47916c5
--- /dev/null
+++ b/dom/events/test/file_bug679494.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+ <title>Test for Bug 679494</title>
+</head>
+<body>
+ There and back again.
+</body>
+</html>
diff --git a/dom/events/test/file_coalesce_touchmove.html b/dom/events/test/file_coalesce_touchmove.html
new file mode 100644
index 0000000000..00172ec596
--- /dev/null
+++ b/dom/events/test/file_coalesce_touchmove.html
@@ -0,0 +1,169 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>touchmove coalescing</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ window.oncontextmenu = function(e) {
+ e.preventDefault();
+ }
+
+ window.addEventListener("touchstart", function(e) { e.preventDefault(); },
+ { passive: false} );
+
+ var touchmoveCount = 0;
+ function touchmove() {
+ // Make touchmove handling slow
+ var start = performance.now();
+ while (performance.now() < (start + 10));
+ ++touchmoveCount;
+ }
+
+ async function fireLotsOfSingleTouchMoves() {
+ var ret = new Promise(function(resolve) {
+ SpecialPowers.loadChromeScript(function() {
+ var element = this.actorParent.rootFrameLoader.ownerElement;
+ var rect = element.getBoundingClientRect();
+ var win = element.ownerDocument.defaultView;
+ var utils = win.windowUtils;
+ var x = rect.x + (rect.width / 2);
+ var y = Math.floor(rect.y + (rect.height / 4));
+ var endY = Math.floor(rect.y + ((rect.height / 4) * 2));
+ utils.sendTouchEvent("touchstart", [0], [x], [y], [1], [1], [0], [1],
+ 0, false);
+ while (y != endY) {
+ utils.sendTouchEvent("touchmove", [0], [x], [y], [1], [1], [0], [1],
+ 0, false);
+ ++y;
+ }
+ utils.sendTouchEvent("touchend", [0], [x], [y], [1], [1], [0], [1],
+ 0, false);
+
+ });
+
+ touchmoveCount = 0;
+ window.addEventListener("touchmove", touchmove, true);
+ window.addEventListener("touchend", function(e) {
+ window.removeEventListener("touchmove", touchmove, true);
+ resolve(touchmoveCount);
+ }, {once: true});
+ });
+
+ return ret
+ }
+
+ async function fireTwoSingleTouches() {
+ var ret = new Promise(function(resolve) {
+ SpecialPowers.loadChromeScript(function() {
+ var element = this.actorParent.rootFrameLoader.ownerElement;
+ var rect = element.getBoundingClientRect();
+ var win = element.ownerDocument.defaultView;
+ var utils = win.windowUtils;
+ var x = rect.x + (rect.width / 2);
+ var startY = Math.floor(rect.y + (rect.height / 4));
+ var endY = Math.floor(rect.y + ((rect.height / 4) * 2));
+ utils.sendTouchEvent("touchstart", [0], [x], [startY], [1], [1], [0],
+ [1], 0, false);
+ utils.sendTouchEvent("touchmove", [0], [x], [startY], [1], [1], [0],
+ [1], 0, false);
+ utils.sendTouchEvent("touchmove", [0], [x], [startY + 1], [1], [1], [0],
+ [1], 0, false);
+ utils.sendTouchEvent("touchend", [0], [x], [endY], [1], [1], [0],
+ [1], 0, false);
+ });
+
+ touchmoveCount = 0;
+ window.addEventListener("touchmove", touchmove, true);
+ window.addEventListener("touchend", function(e) {
+ window.removeEventListener("touchmove", touchmove, true);
+ resolve(touchmoveCount);
+ }, {once: true});
+ });
+
+ return ret
+ }
+
+ async function fireLotsOfMultiTouchMoves() {
+ var ret = new Promise(function(resolve) {
+ SpecialPowers.loadChromeScript(function() {
+ var element = this.actorParent.rootFrameLoader.ownerElement;
+ var rect = element.getBoundingClientRect();
+ var win = element.ownerDocument.defaultView;
+ var utils = win.windowUtils;
+ var x = rect.x + (rect.width / 2);
+ var startY = Math.floor(rect.y + (rect.height / 4));
+ var endY = Math.floor(rect.y + ((rect.height / 4) * 2));
+ utils.sendTouchEvent("touchstart", [0, 1], [x, x + 1],
+ [startY, startY + 1], [1, 1], [1, 1], [0, 0],
+ [1, 1], 0, false);
+ while (startY != endY) {
+ utils.sendTouchEvent("touchmove", [0, 1], [x, x + 1],
+ [startY, startY + 1], [1, 1], [1, 1], [0, 0],
+ [1, 1], 0, false);
+ ++startY;
+ }
+ utils.sendTouchEvent("touchend", [0, 1], [x, x + 1], [endY, endY + 1],
+ [1, 1], [1, 1], [0, 0], [1, 1], 0, false);
+
+ });
+
+ touchmoveCount = 0;
+ window.addEventListener("touchmove", touchmove, true);
+ window.addEventListener("touchend", function(e) {
+ window.removeEventListener("touchmove", touchmove, true);
+ resolve(touchmoveCount);
+ }, {once: true});
+ });
+
+ return ret
+ }
+
+ function disableCoalescing() {
+ return SpecialPowers.pushPrefEnv({"set": [["dom.events.compress.touchmove",
+ false]]});
+ }
+
+ function enableCoalescing() {
+ return SpecialPowers.pushPrefEnv({"set": [["dom.events.compress.touchmove",
+ true]]});
+ }
+
+ async function runTests() {
+ await disableCoalescing();
+ var touchMovesWithoutCoalescing = await fireLotsOfSingleTouchMoves();
+ await enableCoalescing();
+ var touchMovesWithCoalescing = await fireLotsOfSingleTouchMoves();
+ opener.ok(touchMovesWithoutCoalescing > touchMovesWithCoalescing,
+ "Coalescing should reduce the number of touchmove events");
+
+ await disableCoalescing();
+ var twoTouchMovesWithoutCoalescing = await fireTwoSingleTouches();
+ await enableCoalescing();
+ var twoTouchMovesWithCoalescing = await fireTwoSingleTouches();
+ opener.is(twoTouchMovesWithoutCoalescing, 2,
+ "Should have got two touchmoves");
+ opener.is(twoTouchMovesWithoutCoalescing, twoTouchMovesWithCoalescing,
+ "Shouldn't have coalesced the initial touchmove.");
+
+ await disableCoalescing();
+ var multiTouchMovesWithoutCoalescing = await fireLotsOfMultiTouchMoves();
+ await enableCoalescing();
+ var multiTouchMovesWithCoalescing = await fireLotsOfMultiTouchMoves();
+ opener.ok(multiTouchMovesWithoutCoalescing > multiTouchMovesWithCoalescing,
+ "Coalescing should reduce the number of multitouch touchmove events");
+
+ opener.setTimeout("SimpleTest.finish()");
+ window.close();
+ }
+
+ function init() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_touch_events.enabled", true]]},
+ runTests);
+ }
+ </script>
+</head>
+<body onload="SimpleTest.waitForFocus(init);">
+</body>
+</html>
diff --git a/dom/events/test/file_empty.html b/dom/events/test/file_empty.html
new file mode 100644
index 0000000000..9854954ce7
--- /dev/null
+++ b/dom/events/test/file_empty.html
@@ -0,0 +1 @@
+<!DOCTYPE html><html><body></body></html> \ No newline at end of file
diff --git a/dom/events/test/file_event_screenXY.html b/dom/events/test/file_event_screenXY.html
new file mode 100644
index 0000000000..f8b3c361a7
--- /dev/null
+++ b/dom/events/test/file_event_screenXY.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+html, body {
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
+}
+</style>
+<div style="width:100%;height:100%;background-color:red;"></div>
+<script>
+ document.querySelector("div").addEventListener("click", event => {
+ parent.postMessage({ screenX: event.screenX,
+ screenY: event.screenY,
+ clientX: event.clientX,
+ clientY: event.clientY }, "*");
+ });
+ window.onload = () => {
+ parent.postMessage("ready", "*");
+ }
+</script>
diff --git a/dom/events/test/file_focus_blur_on_click_in_cross_origin_iframe.html b/dom/events/test/file_focus_blur_on_click_in_cross_origin_iframe.html
new file mode 100644
index 0000000000..51cc05380f
--- /dev/null
+++ b/dom/events/test/file_focus_blur_on_click_in_cross_origin_iframe.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+html, body {
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
+}
+</style>
+<div style="width:100%;height:100%;background-color:blue;"></div>
+<script>
+ document.querySelector("div").addEventListener("click", event => {
+ parent.postMessage("click", "*");
+ });
+ window.onload = () => {
+ parent.postMessage("ready", "*");
+ };
+ document.body.onfocus = () => {
+ parent.postMessage("focus", "*");
+ };
+ document.body.onblur = () => {
+ parent.postMessage("blur", "*");
+ };
+</script>
diff --git a/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html b/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html
new file mode 100644
index 0000000000..5707366402
--- /dev/null
+++ b/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+html, body {
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
+}
+</style>
+<div style="width:100%;height:100%;background-color:blue;"></div>
+<script>
+ document.querySelector("div").addEventListener("click", event => {
+ parent.postMessage("innerclick", "*");
+ });
+ window.onload = () => {
+ parent.postMessage("innerready", "*");
+ };
+ document.body.onfocus = () => {
+ parent.postMessage("innerfocus", "*");
+ };
+ document.body.onblur = () => {
+ parent.postMessage("innerblur", "*");
+ };
+</script>
diff --git a/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html b/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html
new file mode 100644
index 0000000000..1edabb1e80
--- /dev/null
+++ b/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<style>
+html, body {
+ height: 200px;
+ margin: 0px;
+ padding: 0px;
+}
+</style>
+<body>
+<script>
+ window.addEventListener("message", event => {
+ parent.postMessage(event.data, "*");
+ });
+ window.onload = () => {
+ parent.postMessage("middleready", "*");
+ };
+ document.body.onfocus = () => {
+ parent.postMessage("middlefocus", "*");
+ };
+ document.body.onblur = () => {
+ parent.postMessage("middleblur", "*");
+ };
+</script>
+<div style="width:100px;height:100px;background-color:gray;"></div>
+<iframe width="100" height="100" src="https://example.org/tests/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html"></iframe>
+<script>
+ document.querySelector("div").addEventListener("click", event => {
+ parent.postMessage("middleclick", "*");
+ });
+</script>
diff --git a/dom/events/test/file_mouse_enterleave.html b/dom/events/test/file_mouse_enterleave.html
new file mode 100644
index 0000000000..9e3d1f1d8b
--- /dev/null
+++ b/dom/events/test/file_mouse_enterleave.html
@@ -0,0 +1,40 @@
+<html>
+<body>
+<style>
+#target {
+ width: 100%;
+ height: 100%;
+}
+#reflow {
+ width: 100%;
+ height: 10px;
+ background-color: red;
+}
+</style>
+<div id="target"></div>
+<div id="reflow"></div>
+<script>
+function listener(e) {
+ parent.postMessage({ eventType: e.type, targetName: e.target.localName }, "*");
+}
+
+window.addEventListener("message", function(aEvent) {
+ if (aEvent.data === "reflow") {
+ let reflow = document.getElementById("reflow");
+ reflow.style.display = "none";
+ reflow.getBoundingClientRect();
+ reflow.style.display = "block";
+ reflow.getBoundingClientRect();
+ }
+});
+
+let target = document.getElementById("target");
+target.addEventListener("mouseenter", listener);
+target.addEventListener("mouseleave", listener);
+
+let root = document.documentElement;
+root.addEventListener("mouseenter", listener);
+root.addEventListener("mouseleave", listener);
+</script>
+</body>
+</html>
diff --git a/dom/events/test/mochitest.ini b/dom/events/test/mochitest.ini
new file mode 100644
index 0000000000..4f5731d8f9
--- /dev/null
+++ b/dom/events/test/mochitest.ini
@@ -0,0 +1,251 @@
+[DEFAULT]
+# Skip migration work in BG__migrateUI for browser_startup.js since it increases
+# the occurrence of the leak reported in bug 1398563 with test_bug1327798.html.
+# Run the font-loader eagerly to minimize the risk that font list finalization
+# may disrupt the events received or result in a timeout.
+prefs =
+ browser.migration.version=9999999
+ gfx.font_loader.delay=0
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+support-files =
+ bug226361_iframe.xhtml
+ bug299673.js
+ bug322588-popup.html
+ bug426082.html
+ bug545268.html
+ bug574663.html
+ bug607464.html
+ bug656379-1.html
+ bug418986-3.js
+ error_event_worker.js
+ empty.js
+ event_leak_utils.js
+ window_bug493251.html
+ window_bug659071.html
+ window_wheel_default_action.html
+ !/gfx/layers/apz/test/mochitest/apz_test_utils.js
+
+[test_accel_virtual_modifier.html]
+[test_addEventListenerExtraArg.html]
+[test_all_synthetic_events.html]
+[test_bug1518442.html]
+[test_bug1539497.html]
+[test_bug1686716.html]
+[test_bug226361.xhtml]
+[test_bug238987.html]
+[test_bug288392.html]
+[test_bug299673-1.html]
+[test_bug1037990.html]
+[test_bug299673-2.html]
+[test_bug322588.html]
+[test_bug328885.html]
+[test_bug336682_1.html]
+support-files = test_bug336682.js
+[test_bug367781.html]
+[test_bug379120.html]
+[test_bug402089.html]
+[test_bug405632.html]
+[test_bug409604.html]
+skip-if = toolkit == 'android' #TIMED_OUT
+[test_bug412567.html]
+[test_bug418986-3.html]
+[test_bug422132.html]
+[test_bug426082.html]
+[test_bug427537.html]
+[test_bug428988.html]
+[test_bug432698.html]
+[test_bug443985.html]
+skip-if = verify
+[test_bug447736.html]
+[test_bug448602.html]
+[test_bug450876.html]
+skip-if = verify
+[test_bug456273.html]
+[test_bug457672.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug489671.html]
+[test_bug493251.html]
+[test_bug508479.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM # drag event fails
+[test_bug517851.html]
+[test_bug534833.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug545268.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug547996-1.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug547996-2.xhtml]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug556493.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug563329.html]
+skip-if = true # Disabled due to timeouts.
+[test_bug574663.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug591815.html]
+[test_bug593959.html]
+[test_bug603008.html]
+skip-if = toolkit == 'android'
+[test_bug605242.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug607464.html]
+skip-if = toolkit == 'android' || e10s #CRASH_DUMP, RANDOM, bug 1400586
+[test_bug613634.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug615597.html]
+[test_bug624127.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug635465.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug641477.html]
+[test_bug648573.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug650493.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug656379-1.html]
+skip-if = toolkit == 'android'
+[test_bug656379-2.html]
+skip-if = toolkit == 'android' || (verify && (os == 'linux')) #CRASH_DUMP, RANDOM
+[test_bug656954.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug659071.html]
+[test_bug659350.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug662678.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug667612.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug667919-1.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug684208.html]
+[test_bug689564.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug698929.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_bug704423.html]
+[test_bug741666.html]
+[test_coalesce_touchmove.html]
+support-files = file_coalesce_touchmove.html
+skip-if = debug #In order to be able to test touchmoves, the test needs to synthesize touchstart in a way which asserts
+[test_deviceSensor.html]
+[test_bug812744.html]
+[test_bug822898.html]
+[test_bug855741.html]
+[test_bug864040.html]
+[test_bug924087.html]
+[test_bug930374-content.html]
+[test_bug944011.html]
+[test_bug944847.html]
+[test_bug946632.html]
+[test_bug967796.html]
+[test_bug985988.html]
+[test_bug998809.html]
+[test_bug1003432.html]
+support-files = test_bug1003432.js
+[test_bug1013412.html]
+skip-if = (verify && debug && (os == 'linux' || os == 'win'))
+[test_bug1017086_disable.html]
+support-files = bug1017086_inner.html
+[test_bug1017086_enable.html]
+support-files = bug1017086_inner.html
+[test_bug1079236.html]
+[test_bug1127588.html]
+[test_bug1145910.html]
+[test_bug1150308.html]
+[test_bug1248459.html]
+[test_bug1264380.html]
+[test_bug1327798.html]
+skip-if = headless
+[test_click_on_reframed_generated_text.html]
+[test_click_on_restyled_element.html]
+[test_clickevent_on_input.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_continuous_wheel_events.html]
+skip-if = (verify && debug && (os == 'linux' || os == 'win'))
+[test_dblclick_explicit_original_target.html]
+[test_dom_activate_event.html]
+[test_dom_keyboard_event.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_dom_mouse_event.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_dom_storage_event.html]
+[test_dom_wheel_event.html]
+[test_draggableprop.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_dragstart.html]
+[test_error_events.html]
+skip-if = toolkit == 'android' #TIMED_OUT
+[test_event_handler_cc.html]
+[test_eventctors.html]
+skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
+[test_eventctors_sensors.html]
+[test_disabled_events.html]
+[test_event_screenXY_in_cross_origin_iframe.html]
+support-files =
+ file_event_screenXY.html
+ !/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
+[test_eventhandler_scoping.html]
+[test_eventTimeStamp.html]
+[test_focus_abspos.html]
+[test_legacy_event.html]
+[test_legacy_non-primary_click.html]
+[test_legacy_touch_api.html]
+[test_messageEvent.html]
+[test_messageEvent_init.html]
+[test_mouse_enterleave_iframe.html]
+support-files =
+ file_mouse_enterleave.html
+[test_mouse_capture_iframe.html]
+support-files =
+ file_empty.html
+[test_moz_mouse_pixel_scroll_event.html]
+[test_offsetxy.html]
+[test_onerror_handler_args.html]
+[test_passive_listeners.html]
+[test_paste_image.html]
+skip-if = headless # Bug 1405869
+[test_text_event_in_content.html]
+[test_use_conflated_keypress_event_model_on_newer_Office_Online_Server.html]
+[test_use_split_keypress_event_model_on_old_Confluence.html]
+skip-if = !debug # The mode change event is available only on debug build
+[test_use_split_keypress_event_model_on_old_Office_Online_Server.html]
+skip-if = !debug # The mode change event is available only on debug build
+[test_wheel_default_action.html]
+skip-if = os == 'linux'
+[test_bug687787.html]
+[test_bug1305458.html]
+[test_bug1298970.html]
+[test_bug1304044.html]
+[test_bug1332699.html]
+[test_bug1339758.html]
+[test_bug1369072.html]
+support-files = window_bug1369072.html
+skip-if = toolkit == 'android'
+[test_bug1429572.html]
+support-files = window_bug1429572.html
+[test_bug1446834.html]
+support-files = file_bug1446834.html
+[test_bug1447993.html]
+support-files = window_bug1447993.html
+skip-if = toolkit == 'android'
+[test_bug1484371.html]
+support-files = file_bug1484371.html
+[test_bug1534562.html]
+skip-if = toolkit == 'android' # Bug 1312791
+[test_bug1581192.html]
+[test_bug1673434.html]
+[test_dnd_with_modifiers.html]
+[test_hover_mouseleave.html]
+[test_marquee_events.html]
+[test_slotted_mouse_event.html]
+[test_slotted_text_click.html]
+[test_unbound_before_in_active_chain.html]
+[test_wheel_zoom_on_form_controls.html]
+skip-if = verify
+[test_focus_blur_on_click_in_cross_origin_iframe.html]
+support-files =
+ file_focus_blur_on_click_in_cross_origin_iframe.html
+[test_focus_blur_on_click_in_deep_cross_origin_iframe.html]
+support-files =
+ file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html
+ file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html
diff --git a/dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_1.html b/dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_1.html
new file mode 100644
index 0000000000..55c4e3cad5
--- /dev/null
+++ b/dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_1.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="wpt/pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <!--script src="/resources/testharnessreport.js"></script-->
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="wpt/pointerevent_support.js"></script>
+ <script>
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("implicit pointer capture for touch");
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ let target0 = window.document.getElementById("target0");
+ let target1 = window.document.getElementById("target1");
+
+ on_event(target0, "pointerdown", function (event) {
+ pointerdown_event = event;
+ detected_pointertypes[event.pointerType] = true;
+ assert_true(true, "target0 receives pointerdown");
+ });
+
+ on_event(target0, "pointermove", function (event) {
+ assert_true(true, "target0 receives pointermove");
+ assert_true(target0.hasPointerCapture(event.pointerId), "target0.hasPointerCapture should be true");
+ });
+
+ on_event(target0, "gotpointercapture", function (event) {
+ assert_true(true, "target0 should receive gotpointercapture");
+ });
+
+ on_event(target0, "lostpointercapture", function (event) {
+ assert_true(true, "target0 should receive lostpointercapture");
+ });
+
+ on_event(target1, "pointermove", function (event) {
+ assert_true(false, "target1 should not receive pointermove");
+ });
+
+ on_event(target0, "pointerup", function (event) {
+ assert_true(true, "target0 receives pointerup");
+ test_pointerEvent.done();
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events tests</h1>
+ <div id="target0" style="width: 200px; height: 200px; background: green" touch-action:none></div>
+ <div id="target1" style="width: 200px; height: 200px; background: green" touch-action:none></div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_2.html b/dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_2.html
new file mode 100644
index 0000000000..a533429acb
--- /dev/null
+++ b/dom/events/test/pointerevents/bug1293174_implicit_pointer_capture_for_touch_2.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="wpt/pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <!--script src="/resources/testharnessreport.js"></script-->
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="wpt/pointerevent_support.js"></script>
+ <script>
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("implicit pointer capture for touch");
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ let target0 = window.document.getElementById("target0");
+ let target1 = window.document.getElementById("target1");
+
+ on_event(target0, "pointerdown", function (event) {
+ pointerdown_event = event;
+ detected_pointertypes[event.pointerType] = true;
+ assert_true(true, "target0 receives pointerdown");
+ });
+
+ on_event(target0, "pointermove", function (event) {
+ assert_true(true, "target0 receives pointermove");
+ assert_false(target0.hasPointerCapture(event.pointerId), "target0.hasPointerCapture should be false");
+ });
+
+ on_event(target0, "gotpointercapture", function (event) {
+ assert_unreached("target0 should not receive gotpointercapture");
+ });
+
+ on_event(target0, "lostpointercapture", function (event) {
+ assert_unreached("target0 should not receive lostpointercapture");
+ });
+
+ on_event(target1, "pointermove", function (event) {
+ assert_true(true, "target1 receives pointermove");
+ assert_false(target1.hasPointerCapture(event.pointerId), "target1.hasPointerCapture should be false");
+ });
+
+ on_event(target0, "pointerup", function (event) {
+ assert_true(true, "target0 receives pointerup");
+ test_pointerEvent.done();
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events tests</h1>
+ <div id="target0" style="width: 200px; height: 200px; background: green" touch-action:none></div>
+ <div id="target1" style="width: 200px; height: 200px; background: green" touch-action:none></div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/bug_1420589_iframe1.html b/dom/events/test/pointerevents/bug_1420589_iframe1.html
new file mode 100644
index 0000000000..b18d808b84
--- /dev/null
+++ b/dom/events/test/pointerevents/bug_1420589_iframe1.html
@@ -0,0 +1,17 @@
+<body>
+ <script>
+ let touchEvents = ["touchstart", "touchmove", "touchend"];
+ let pointerEvents = ["pointerdown", "pointermove", "pointerup"];
+
+ touchEvents.forEach((event) => {
+ document.addEventListener(event, (e) => {
+ parent.postMessage("iframe1 " + e.type, "*");
+ }, { once: true });
+ });
+ pointerEvents.forEach((event) => {
+ document.addEventListener(event, (e) => {
+ parent.postMessage("iframe1 " + e.type, "*");
+ }, { once: true });
+ });
+ </script>
+</body>
diff --git a/dom/events/test/pointerevents/bug_1420589_iframe2.html b/dom/events/test/pointerevents/bug_1420589_iframe2.html
new file mode 100644
index 0000000000..75aea1d187
--- /dev/null
+++ b/dom/events/test/pointerevents/bug_1420589_iframe2.html
@@ -0,0 +1,17 @@
+<body>
+ <script>
+ let touchEvents = ["touchstart", "touchmove", "touchend"];
+ let pointerEvents = ["pointerdown", "pointermove", "pointerup"];
+
+ touchEvents.forEach((event) => {
+ document.addEventListener(event, (e) => {
+ parent.postMessage("iframe2 " + e.type, "*");
+ }, { once: true });
+ });
+ pointerEvents.forEach((event) => {
+ document.addEventListener(event, (e) => {
+ parent.postMessage("iframe2 " + e.type, "*");
+ }, { once: true });
+ });
+ </script>
+</body>
diff --git a/dom/events/test/pointerevents/file_pointercapture_xorigin_iframe.html b/dom/events/test/pointerevents/file_pointercapture_xorigin_iframe.html
new file mode 100644
index 0000000000..88690748e5
--- /dev/null
+++ b/dom/events/test/pointerevents/file_pointercapture_xorigin_iframe.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1671849
+-->
+<head>
+<title>Bug 1671849</title>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="pointerevent_utils.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+iframe {
+ width: 400px;
+ height: 300px;
+ border: 1px solid blue;
+}
+</style>
+</head>
+<body>
+<a target="_blank"href="https://bugzilla.mozilla.org/show_bug.cgi?id=1671849">Mozilla Bug 1671849</a>
+<div id="target"></div>
+<iframe src="https://example.com/tests/dom/events/test/pointerevents/iframe.html"></iframe>
+
+<pre id="test">
+<script type="text/javascript">
+/**
+ * Test for Bug 1671849
+ */
+add_task(async function test_pointer_capture_xorigin_iframe() {
+ let iframe = document.querySelector("iframe");
+ await SpecialPowers.spawn(iframe.contentWindow, [], () => {
+ let unexpected = function(e) {
+ ok(false, `iframe shoule not get any ${e.type} event`);
+ };
+ content.document.body.addEventListener("pointermove", unexpected);
+ content.document.body.addEventListener("pointerup", unexpected);
+ });
+
+ let target = document.getElementById("target");
+ synthesizeMouse(target, 10, 10, { type: "mousedown" });
+ await waitForEvent(target, "pointerdown", function(e) {
+ target.setPointerCapture(e.pointerId);
+ });
+
+ synthesizeMouse(iframe, 10, 10, { type: "mousemove" });
+ await Promise.all([waitForEvent(target, "gotpointercapture"),
+ waitForEvent(target, "pointermove")]);
+
+ synthesizeMouse(iframe, 10, 10, { type: "mouseup" });
+ await Promise.all([waitForEvent(target, "lostpointercapture"),
+ waitForEvent(target, "pointerup")]);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/file_pointercapture_xorigin_iframe_pointerlock.html b/dom/events/test/pointerevents/file_pointercapture_xorigin_iframe_pointerlock.html
new file mode 100644
index 0000000000..12174da197
--- /dev/null
+++ b/dom/events/test/pointerevents/file_pointercapture_xorigin_iframe_pointerlock.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1671849
+-->
+<head>
+<title>Bug 1671849</title>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="pointerevent_utils.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+iframe {
+ width: 400px;
+ height: 300px;
+ border: 1px solid blue;
+}
+</style>
+</head>
+<body>
+<a target="_blank"href="https://bugzilla.mozilla.org/show_bug.cgi?id=1671849">Mozilla Bug 1671849</a>
+<div id="target"></div>
+<iframe src="https://example.com/tests/dom/events/test/pointerevents/iframe.html"></iframe>
+
+<pre id="test">
+<script type="text/javascript">
+/**
+ * Test for Bug 1671849
+ */
+function requestPointerLockOnRemoteTarget(aRemoteTarget, aTagName) {
+ return SpecialPowers.spawn(aRemoteTarget, [aTagName], async (tagName) => {
+ SpecialPowers.wrap(content.document).notifyUserGestureActivation();
+ let target = content.document.querySelector(tagName);
+ target.requestPointerLock();
+ await new Promise((aResolve) => {
+ let eventHandler = function(e) {
+ is(e.type, "pointerlockchange", `Got ${e.type} on iframe`);
+ is(content.document.pointerLockElement, target, `pointer lock element`);
+ content.document.removeEventListener("pointerlockchange", eventHandler);
+ content.document.removeEventListener("pointerlockerror", eventHandler);
+ aResolve();
+ };
+ content.document.addEventListener("pointerlockchange", eventHandler);
+ content.document.addEventListener("pointerlockerror", eventHandler);
+ });
+ });
+}
+
+function exitPointerLockOnRemoteTarget(aRemoteTarget) {
+ return SpecialPowers.spawn(aRemoteTarget, [], async () => {
+ content.document.exitPointerLock();
+ await new Promise((aResolve) => {
+ let eventHandler = function(e) {
+ is(e.type, "pointerlockchange", `Got ${e.type} on iframe`);
+ is(content.document.pointerLockElement, null, `pointer lock element`);
+ content.document.removeEventListener("pointerlockchange", eventHandler);
+ content.document.removeEventListener("pointerlockerror", eventHandler);
+ aResolve();
+ };
+ content.document.addEventListener("pointerlockchange", eventHandler);
+ content.document.addEventListener("pointerlockerror", eventHandler);
+ });
+ });
+}
+
+function waitEventOnRemoteTarget(aRemoteTarget, aEventName) {
+ return SpecialPowers.spawn(aRemoteTarget, [aEventName], async (eventName) => {
+ await new Promise((aResolve) => {
+ content.document.body.addEventListener(eventName, (e) => {
+ ok(true, `got ${e.type} event on ${e.target}`);
+ aResolve();
+ }, { once: true });
+ });
+ });
+}
+
+add_task(async function test_pointer_capture_xorigin_iframe_pointer_lock() {
+ await SimpleTest.promiseFocus();
+
+ // Request pointer capture on top-level.
+ let target = document.getElementById("target");
+ synthesizeMouse(target, 10, 10, { type: "mousedown" });
+ await waitForEvent(target, "pointerdown", function(e) {
+ target.setPointerCapture(e.pointerId);
+ });
+
+ let iframe = document.querySelector("iframe");
+ synthesizeMouse(iframe, 10, 10, { type: "mousemove" });
+ await Promise.all([waitForEvent(target, "gotpointercapture"),
+ waitForEvent(target, "pointermove")]);
+
+ // Request pointer lock on iframe.
+ let iframeWin = iframe.contentWindow;
+ await Promise.all([requestPointerLockOnRemoteTarget(iframeWin, "div"),
+ waitForEvent(target, "lostpointercapture")]);
+
+ // Exit pointer lock on iframe.
+ await exitPointerLockOnRemoteTarget(iframeWin);
+
+ synthesizeMouse(target, 10, 10, { type: "mouseup" });
+ await waitForEvent(target, "pointerup");
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/file_test_trigger_fullscreen.html b/dom/events/test/pointerevents/file_test_trigger_fullscreen.html
new file mode 100644
index 0000000000..2d6549ede7
--- /dev/null
+++ b/dom/events/test/pointerevents/file_test_trigger_fullscreen.html
@@ -0,0 +1 @@
+<body><div id='target' style='width: 50px; height: 50px; background: green'></div></body>
diff --git a/dom/events/test/pointerevents/iframe.html b/dom/events/test/pointerevents/iframe.html
new file mode 100644
index 0000000000..0e3eac19b9
--- /dev/null
+++ b/dom/events/test/pointerevents/iframe.html
@@ -0,0 +1,7 @@
+<html>
+ <head>
+ </head>
+ <body>
+ <div id="div"></div><input>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/mochitest.ini b/dom/events/test/pointerevents/mochitest.ini
new file mode 100644
index 0000000000..7f44b3cbae
--- /dev/null
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -0,0 +1,116 @@
+[DEFAULT]
+support-files =
+ iframe.html
+ mochitest_support_external.js
+ mochitest_support_internal.js
+ wpt/pointerevent_styles.css
+ wpt/pointerevent_support.js
+ pointerevent_utils.js
+ !/gfx/layers/apz/test/mochitest/apz_test_utils.js
+
+[test_bug1285128.html]
+[test_bug1293174_implicit_pointer_capture_for_touch_1.html]
+support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
+[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
+support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
+[test_bug1303704.html]
+[test_bug1315862.html]
+[test_bug1323158.html]
+[test_bug1403055.html]
+[test_bug1420589_1.html]
+support-files =
+ bug_1420589_iframe1.html
+ bug_1420589_iframe2.html
+[test_bug1420589_2.html]
+support-files =
+ bug_1420589_iframe1.html
+[test_bug1420589_3.html]
+support-files =
+ bug_1420589_iframe1.html
+[test_multiple_touches.html]
+[test_wpt_pointerevent_attributes_hoverable_pointers-manual.html]
+support-files =
+ wpt/pointerevent_attributes_hoverable_pointers-manual.html
+ wpt/resources/pointerevent_attributes_hoverable_pointers-iframe.html
+[test_wpt_pointerevent_attributes_nohover_pointers-manual.html]
+support-files =
+ wpt/pointerevent_attributes_nohover_pointers-manual.html
+ wpt/resources/pointerevent_attributes_hoverable_pointers-iframe.html
+[test_wpt_pointerevent_boundary_events_in_capturing-manual.html]
+support-files = wpt/pointerevent_boundary_events_in_capturing-manual.html
+[test_wpt_pointerevent_change-touch-action-onpointerdown_touch-manual.html]
+support-files = wpt/pointerevent_change-touch-action-onpointerdown_touch-manual.html
+disabled = disabled
+[test_wpt_pointerevent_constructor.html]
+support-files = wpt/pointerevent_constructor.html
+[test_wpt_pointerevent_multiple_primary_pointers_boundary_events-manual.html]
+support-files = wpt/pointerevent_multiple_primary_pointers_boundary_events-manual.html
+disabled = should be investigated
+[test_wpt_pointerevent_pointercancel_touch-manual.html]
+support-files = wpt/pointerevent_pointercancel_touch-manual.html
+[test_wpt_pointerevent_pointerId_scope-manual.html]
+support-files = wpt/resources/pointerevent_pointerId_scope-iframe.html
+disabled = should be investigated
+[test_wpt_pointerevent_pointerleave_after_pointercancel_touch-manual.html]
+support-files = wpt/pointerevent_pointerleave_after_pointercancel_touch-manual.html
+[test_wpt_pointerevent_pointerleave_pen-manual.html]
+support-files = wpt/pointerevent_pointerleave_pen-manual.html
+[test_wpt_pointerevent_pointerout_after_pointercancel_touch-manual.html]
+support-files = wpt/pointerevent_pointerout_after_pointercancel_touch-manual.html
+[test_wpt_pointerevent_pointerout_pen-manual.html]
+support-files = wpt/pointerevent_pointerout_pen-manual.html
+[test_wpt_pointerevent_releasepointercapture_events_to_original_target-manual.html]
+support-files = wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html
+[test_wpt_pointerevent_releasepointercapture_onpointercancel_touch-manual.html]
+support-files = wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html
+[test_wpt_pointerevent_sequence_at_implicit_release_on_drag-manual.html]
+support-files = wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.html
+[test_wpt_pointerevent_drag_interaction-manual.html]
+support-files = wpt/html/pointerevent_drag_interaction-manual.html
+[test_wpt_touch_action.html]
+skip-if = os == 'android' # Bug 1312791
+support-files =
+ ../../../../gfx/layers/apz/test/mochitest/apz_test_utils.js
+ ../../../../gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
+ touch_action_helpers.js
+ wpt/pointerevent_touch-action-auto-css_touch-manual.html
+ wpt/pointerevent_touch-action-button-test_touch-manual.html
+ wpt/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html
+ wpt/pointerevent_touch-action-inherit_child-none_touch-manual.html
+ wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html
+ wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html
+ wpt/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html
+ wpt/pointerevent_touch-action-inherit_parent-none_touch-manual.html
+ wpt/pointerevent_touch-action-none-css_touch-manual.html
+ wpt/pointerevent_touch-action-pan-x-css_touch-manual.html
+ wpt/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html
+ wpt/pointerevent_touch-action-pan-x-pan-y_touch-manual.html
+ wpt/pointerevent_touch-action-pan-y-css_touch-manual.html
+ wpt/pointerevent_touch-action-span-test_touch-manual.html
+ wpt/pointerevent_touch-action-svg-test_touch-manual.html
+ wpt/pointerevent_touch-action-table-test_touch-manual.html
+ wpt/pointerevent_touch-action-pan-down-css_touch-manual.html
+ wpt/pointerevent_touch-action-pan-left-css_touch-manual.html
+ wpt/pointerevent_touch-action-pan-right-css_touch-manual.html
+ wpt/pointerevent_touch-action-pan-up-css_touch-manual.html
+[test_wpt_pointerevent_movementxy-manual.html]
+support-files =
+ wpt/pointerlock/pointerevent_movementxy-manual.html
+ wpt/pointerlock/resources/pointerevent_movementxy-iframe.html
+[test_wpt_pointerevent_releasepointercapture_pointerup_touch.html]
+support-files = wpt/pointerevent_releasepointercapture_pointerup_touch.html
+[test_wpt_pointerevent_setpointercapture_pointerup_touch.html]
+support-files = wpt/pointerevent_setpointercapture_pointerup_touch.html
+[test_trigger_fullscreen_by_pointer_events.html]
+support-files =
+ file_test_trigger_fullscreen.html
+[test_remove_frame_when_got_pointer_capture.html]
+[test_getCoalescedEvents.html]
+skip-if =
+ !e10s || os == 'android' # Bug 1312791
+ verify && os == 'win' # Bug 1659744
+[test_pointercapture_xorigin_iframe.html]
+support-files =
+ file_pointercapture_xorigin_iframe.html
+ file_pointercapture_xorigin_iframe_pointerlock.html
+[test_pointercapture_remove_iframe.html]
diff --git a/dom/events/test/pointerevents/mochitest_support_external.js b/dom/events/test/pointerevents/mochitest_support_external.js
new file mode 100644
index 0000000000..e1ffabcccf
--- /dev/null
+++ b/dom/events/test/pointerevents/mochitest_support_external.js
@@ -0,0 +1,286 @@
+// This file supports translating W3C tests
+// to tests on auto MochiTest system with minimum changes.
+// Author: Maksim Lebedev <alessarik@gmail.com>
+
+// Function allows to prepare our tests after load document
+addEventListener(
+ "load",
+ function(event) {
+ console.log("OnLoad external document");
+ prepareTest();
+ },
+ false
+);
+
+// Function allows to initialize prerequisites before testing
+function prepareTest() {
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestCompleteLog();
+ turnOnPointerEvents(startTest);
+}
+
+function setImplicitPointerCapture(capture, callback) {
+ console.log("SET dom.w3c_pointer_events.implicit_capture as " + capture);
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [["dom.w3c_pointer_events.implicit_capture", capture]],
+ },
+ callback
+ );
+}
+
+function turnOnPointerEvents(callback) {
+ console.log("SET dom.w3c_pointer_events.enabled as TRUE");
+ console.log("SET layout.css.touch_action.enabled as TRUE");
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [
+ ["dom.w3c_pointer_events.enabled", true],
+ ["layout.css.touch_action.enabled", true],
+ ],
+ },
+ callback
+ );
+}
+
+var utils = SpecialPowers.Ci.nsIDOMWindowUtils;
+
+// Mouse Event Helper Object
+var MouseEventHelper = (function() {
+ return {
+ MOUSE_ID: utils.DEFAULT_MOUSE_POINTER_ID,
+ PEN_ID: utils.DEFAULT_PEN_POINTER_ID,
+ // State
+ // TODO: Separate this to support mouse and pen simultaneously.
+ BUTTONS_STATE: utils.MOUSE_BUTTONS_NO_BUTTON,
+
+ // Button
+ BUTTON_NONE: -1, // Used by test framework only. (replaced before sending)
+ BUTTON_LEFT: utils.MOUSE_BUTTON_LEFT_BUTTON,
+ BUTTON_MIDDLE: utils.MOUSE_BUTTON_MIDDLE_BUTTON,
+ BUTTON_RIGHT: utils.MOUSE_BUTTON_RIGHT_BUTTON,
+
+ // Buttons
+ BUTTONS_NONE: utils.MOUSE_BUTTONS_NO_BUTTON,
+ BUTTONS_LEFT: utils.MOUSE_BUTTONS_LEFT_BUTTON,
+ BUTTONS_MIDDLE: utils.MOUSE_BUTTONS_MIDDLE_BUTTON,
+ BUTTONS_RIGHT: utils.MOUSE_BUTTONS_RIGHT_BUTTON,
+ BUTTONS_4TH: utils.MOUSE_BUTTONS_4TH_BUTTON,
+ BUTTONS_5TH: utils.MOUSE_BUTTONS_5TH_BUTTON,
+
+ // Utils
+ computeButtonsMaskFromButton(aButton) {
+ // Since the range of button values is 0 ~ 2 (see nsIDOMWindowUtils.idl),
+ // we can use an array to find out the desired mask.
+ var mask = [
+ this.BUTTONS_NONE, // -1 (MouseEventHelper.BUTTON_NONE)
+ this.BUTTONS_LEFT, // 0
+ this.BUTTONS_MIDDLE, // 1
+ this.BUTTONS_RIGHT, // 2
+ ][aButton + 1];
+
+ ok(mask !== undefined, "Unrecognized button value caught!");
+ return mask;
+ },
+
+ checkExitState() {
+ ok(!this.BUTTONS_STATE, "Mismatched mousedown/mouseup caught.");
+ },
+ };
+})();
+
+function createMouseEvent(aEventType, aParams) {
+ var eventObj = { type: aEventType };
+
+ // Default to mouse.
+ eventObj.inputSource =
+ aParams && "inputSource" in aParams
+ ? aParams.inputSource
+ : MouseEvent.MOZ_SOURCE_MOUSE;
+ // Compute pointerId
+ eventObj.id =
+ eventObj.inputSource === MouseEvent.MOZ_SOURCE_MOUSE
+ ? MouseEventHelper.MOUSE_ID
+ : MouseEventHelper.PEN_ID;
+ // Check or generate a |button| value.
+ var isButtonEvent = aEventType === "mouseup" || aEventType === "mousedown";
+
+ // Set |button| to the default value first.
+ eventObj.button = isButtonEvent
+ ? MouseEventHelper.BUTTON_LEFT
+ : MouseEventHelper.BUTTON_NONE;
+
+ // |button| is passed, use and check it.
+ if (aParams && "button" in aParams) {
+ var hasButtonValue = aParams.button !== MouseEventHelper.BUTTON_NONE;
+ ok(
+ !isButtonEvent || hasButtonValue,
+ "Inappropriate |button| value caught."
+ );
+ eventObj.button = aParams.button;
+ }
+
+ // Generate a |buttons| value and update buttons state
+ var buttonsMask = MouseEventHelper.computeButtonsMaskFromButton(
+ eventObj.button
+ );
+ switch (aEventType) {
+ case "mousedown":
+ MouseEventHelper.BUTTONS_STATE |= buttonsMask; // Set button flag.
+ break;
+ case "mouseup":
+ MouseEventHelper.BUTTONS_STATE &= ~buttonsMask; // Clear button flag.
+ break;
+ }
+ eventObj.buttons = MouseEventHelper.BUTTONS_STATE;
+
+ // Replace the button value for mousemove events.
+ // Since in widget level design, even when no button is pressed at all, the
+ // value of WidgetMouseEvent.button is still 0, which is the same value as
+ // the one for mouse left button.
+ if (aEventType === "mousemove") {
+ eventObj.button = MouseEventHelper.BUTTON_LEFT;
+ }
+ return eventObj;
+}
+
+// Helper function to send MouseEvent with different parameters
+function sendMouseEvent(int_win, elemId, mouseEventType, params) {
+ var elem = int_win.document.getElementById(elemId);
+ if (elem) {
+ var rect = elem.getBoundingClientRect();
+ var eventObj = createMouseEvent(mouseEventType, params);
+
+ // Default to the center of the target element but we can still send to a
+ // position outside of the target element.
+ var offsetX =
+ params && "offsetX" in params ? params.offsetX : rect.width / 2;
+ var offsetY =
+ params && "offsetY" in params ? params.offsetY : rect.height / 2;
+
+ console.log(elemId, eventObj);
+ synthesizeMouse(elem, offsetX, offsetY, eventObj, int_win);
+ } else {
+ is(!!elem, true, "Document should have element with id: " + elemId);
+ }
+}
+
+// Helper function to send MouseEvent with position
+function sendMouseEventAtPoint(aWindow, aLeft, aTop, aMouseEventType, aParams) {
+ var eventObj = createMouseEvent(aMouseEventType, aParams);
+ console.log(eventObj);
+ synthesizeMouseAtPoint(aLeft, aTop, eventObj, aWindow);
+}
+
+// Touch Event Helper Object
+var TouchEventHelper = {
+ // State
+ TOUCH_ID: utils.DEFAULT_TOUCH_POINTER_ID,
+ TOUCH_STATE: false,
+
+ // Utils
+ checkExitState() {
+ ok(!this.TOUCH_STATE, "Mismatched touchstart/touchend caught.");
+ },
+};
+
+// Helper function to send TouchEvent with different parameters
+// TODO: Support multiple touch points to test more features such as
+// PointerEvent.isPrimary and pinch-zoom.
+function sendTouchEvent(int_win, elemId, touchEventType, params) {
+ var elem = int_win.document.getElementById(elemId);
+ if (elem) {
+ var rect = elem.getBoundingClientRect();
+ var eventObj = {
+ type: touchEventType,
+ id: TouchEventHelper.TOUCH_ID,
+ };
+
+ // Update touch state
+ switch (touchEventType) {
+ case "touchstart":
+ TouchEventHelper.TOUCH_STATE = true; // Set touch flag.
+ break;
+ case "touchend":
+ case "touchcancel":
+ TouchEventHelper.TOUCH_STATE = false; // Clear touch flag.
+ break;
+ }
+
+ // Default to the center of the target element but we can still send to a
+ // position outside of the target element.
+ var offsetX =
+ params && "offsetX" in params ? params.offsetX : rect.width / 2;
+ var offsetY =
+ params && "offsetY" in params ? params.offsetY : rect.height / 2;
+
+ console.log(elemId, eventObj);
+ synthesizeTouch(elem, offsetX, offsetY, eventObj, int_win);
+ } else {
+ is(!!elem, true, "Document should have element with id: " + elemId);
+ }
+}
+
+// Helper function to trigger drag and drop.
+async function doDragAndDrop(int_win, srcElemId, destElemId, params = {}) {
+ params.srcElement = int_win.document.getElementById(srcElemId);
+ params.destElement = int_win.document.getElementById(destElemId);
+ params.srcWindow = int_win;
+ params.destWindow = int_win;
+ params.id = MouseEventHelper.MOUSE_ID;
+ // This is basically for android which has a larger drag threshold.
+ params.stepY = params.stepY || 25;
+ await synthesizePlainDragAndDrop(params);
+}
+
+// Helper function to run Point Event test in a new tab.
+function runTestInNewWindow(aFile) {
+ var testURL =
+ location.href.substring(0, location.href.lastIndexOf("/") + 1) + aFile;
+ var testWindow = window.open(testURL, "_blank");
+ var testDone = false;
+
+ // We start testing when receiving load event. Inject the mochitest helper js
+ // to the test case after DOM elements are constructed and before the load
+ // event is fired.
+ testWindow.addEventListener(
+ "DOMContentLoaded",
+ function() {
+ var e = testWindow.document.createElement("script");
+ e.type = "text/javascript";
+ e.src =
+ "../".repeat(aFile.split("/").length - 1) +
+ "mochitest_support_internal.js";
+ testWindow.document.getElementsByTagName("head")[0].appendChild(e);
+ },
+ { once: true }
+ );
+
+ window.addEventListener("message", function(aEvent) {
+ switch (aEvent.data.type) {
+ case "START":
+ // Update constants
+ MouseEventHelper.MOUSE_ID = aEvent.data.message.mouseId;
+ MouseEventHelper.PEN_ID = aEvent.data.message.penId;
+ TouchEventHelper.TOUCH_ID = aEvent.data.message.touchId;
+
+ turnOnPointerEvents(() => {
+ executeTest(testWindow);
+ });
+ return;
+ case "RESULT":
+ // Should not perform checking after SimpleTest.finish().
+ if (!testDone) {
+ ok(aEvent.data.result, aEvent.data.message);
+ }
+ return;
+ case "FIN":
+ testDone = true;
+ MouseEventHelper.checkExitState();
+ TouchEventHelper.checkExitState();
+ testWindow.close();
+ SimpleTest.finish();
+ return;
+ }
+ });
+}
diff --git a/dom/events/test/pointerevents/mochitest_support_internal.js b/dom/events/test/pointerevents/mochitest_support_internal.js
new file mode 100644
index 0000000000..cdc10a3181
--- /dev/null
+++ b/dom/events/test/pointerevents/mochitest_support_internal.js
@@ -0,0 +1,125 @@
+// This file supports translating W3C tests
+// to tests on auto MochiTest system with minimum changes.
+// Author: Maksim Lebedev <alessarik@gmail.com>
+
+const PARENT_ORIGIN = "http://mochi.test:8888/";
+
+// Since web platform tests don't check pointerId, we have to use some heuristic
+// to test them. and thus pointerIds are send to mochitest_support_external.js
+// before we start sending synthesized widget events. Here, we avoid using
+// default values used in Gecko to insure everything works as expected.
+const POINTER_MOUSE_ID = 7;
+const POINTER_PEN_ID = 8;
+const POINTER_TOUCH_ID = 9; // Extend for multiple touch points if needed.
+
+// Setup environment.
+addListeners(document.getElementById("target0"));
+addListeners(document.getElementById("target1"));
+
+// Setup communication between mochitest_support_external.js.
+// Function allows to initialize prerequisites before testing
+// and adds some callbacks to support mochitest system.
+function resultCallback(aTestObj) {
+ var message = aTestObj.name + " (";
+ message += "Get: " + JSON.stringify(aTestObj.status) + ", ";
+ message += "Expect: " + JSON.stringify(aTestObj.PASS) + ")";
+ window.opener.postMessage(
+ {
+ type: "RESULT",
+ message,
+ result: aTestObj.status === aTestObj.PASS,
+ },
+ PARENT_ORIGIN
+ );
+}
+
+add_result_callback(resultCallback);
+add_completion_callback(() => {
+ window.opener.postMessage({ type: "FIN" }, PARENT_ORIGIN);
+});
+
+window.addEventListener("load", () => {
+ // Start testing.
+ var startMessage = {
+ type: "START",
+ message: {
+ mouseId: POINTER_MOUSE_ID,
+ penId: POINTER_PEN_ID,
+ touchId: POINTER_TOUCH_ID,
+ },
+ };
+ window.opener.postMessage(startMessage, PARENT_ORIGIN);
+});
+
+function addListeners(elem) {
+ if (!elem) {
+ return;
+ }
+ var All_Events = [
+ "pointerdown",
+ "pointerup",
+ "pointercancel",
+ "pointermove",
+ "pointerover",
+ "pointerout",
+ "pointerenter",
+ "pointerleave",
+ "gotpointercapture",
+ "lostpointercapture",
+ ];
+ All_Events.forEach(function(name) {
+ elem.addEventListener(name, function(event) {
+ console.log("(" + event.type + ")-(" + event.pointerType + ")");
+
+ // Perform checks only for trusted events.
+ if (!event.isTrusted) {
+ return;
+ }
+
+ // Compute the desired event.pointerId from event.pointerType.
+ var pointerId = {
+ mouse: POINTER_MOUSE_ID,
+ pen: POINTER_PEN_ID,
+ touch: POINTER_TOUCH_ID,
+ }[event.pointerType];
+
+ // Compare the pointerId.
+ resultCallback({
+ name: "Mismatched event.pointerId recieved.",
+ status: event.pointerId,
+ PASS: pointerId,
+ });
+ });
+ });
+}
+
+// mock the touchScrollInTarget to make the test work.
+function touchScrollInTarget() {
+ return Promise.resolve();
+}
+
+// mock test_driver to make the test work.
+function Actions() {}
+Actions.prototype = {
+ addPointer() {
+ return this;
+ },
+ pointerMove() {
+ return this;
+ },
+ pointerDown() {
+ return this;
+ },
+ pause() {
+ return this;
+ },
+ pointerUp() {
+ return this;
+ },
+ send() {
+ return Promise.resolve();
+ },
+};
+const test_driver = {
+ Actions,
+};
diff --git a/dom/events/test/pointerevents/pointerevent_utils.js b/dom/events/test/pointerevents/pointerevent_utils.js
new file mode 100644
index 0000000000..44a945adf8
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_utils.js
@@ -0,0 +1,60 @@
+// Get test filename for page being run in popup so errors are more useful
+var testName = location.pathname.split("/").pop();
+
+// Wrap test functions and pass to parent window
+window.ok = function(a, msg) {
+ opener.ok(a, testName + ": " + msg);
+};
+
+window.is = function(a, b, msg) {
+ opener.is(a, b, testName + ": " + msg);
+};
+
+window.isnot = function(a, b, msg) {
+ opener.isnot(a, b, testName + ": " + msg);
+};
+
+window.todo = function(a, msg) {
+ opener.todo(a, testName + ": " + msg);
+};
+
+window.todo_is = function(a, b, msg) {
+ opener.todo_is(a, b, testName + ": " + msg);
+};
+
+window.todo_isnot = function(a, b, msg) {
+ opener.todo_isnot(a, b, testName + ": " + msg);
+};
+
+window.info = function(msg) {
+ opener.info(testName + ": " + msg);
+};
+
+// Override bits of SimpleTest so test files work stand-alone
+var SimpleTest = SimpleTest || {};
+
+SimpleTest.waitForExplicitFinish = function() {
+ dump("[POINTEREVENT] Starting " + testName + "\n");
+};
+
+SimpleTest.finish = function() {
+ dump("[POINTEREVENT] Finishing " + testName + "\n");
+ opener.nextTest();
+};
+
+// Utility functions
+function waitForEvent(aTarget, aEvent, aCallback) {
+ return new Promise(aResolve => {
+ aTarget.addEventListener(
+ aEvent,
+ e => {
+ ok(true, `got ${e.type} event on ${e.target.id}`);
+ if (aCallback) {
+ aCallback(e);
+ }
+ aResolve();
+ },
+ { once: true }
+ );
+ });
+}
diff --git a/dom/events/test/pointerevents/readme.md b/dom/events/test/pointerevents/readme.md
new file mode 100644
index 0000000000..0cc0190979
--- /dev/null
+++ b/dom/events/test/pointerevents/readme.md
@@ -0,0 +1,9 @@
+Directory for Pointer Events Tests
+
+Latest Editor's Draft: https://w3c.github.io/pointerevents/
+
+Latest W3C Technical Report: http://www.w3.org/TR/pointerevents/
+
+Discussion forum for tests: http://lists.w3.org/Archives/Public/public-test-infra/
+
+Test Assertion table: https://www.w3.org/wiki/PointerEvents/TestAssertions
diff --git a/dom/events/test/pointerevents/test_bug1285128.html b/dom/events/test/pointerevents/test_bug1285128.html
new file mode 100644
index 0000000000..749891d9b2
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1285128.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1285128
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1285128</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1285128">Mozilla Bug 1285128</a>
+<p id="display"></p>
+<div id="target0" style="width: 50px; height: 50px; background: green"></div>
+<div id="target1" style="width: 50px; height: 50px; background: red"></div>
+<script type="text/javascript">
+
+/** Test for Bug 1285128 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let target0 = window.document.getElementById("target0");
+ let pointerEventsList = ["pointerover", "pointerenter", "pointerdown",
+ "pointerup", "pointerleave", "pointerout"];
+ let receivedPointerEvents = false;
+ pointerEventsList.forEach((elem, index, arr) => {
+ target0.addEventListener(elem, (event) => {
+ ok(false, "receiving event " + event.type);
+ receivedPointerEvents = true;
+ });
+ });
+
+ target1.addEventListener("mouseup", () => {
+ ok(!receivedPointerEvents, "synthesized mousemove should not trigger any pointer events");
+ SimpleTest.finish();
+ });
+
+ synthesizeMouseAtCenter(target0, { type: "mousemove",
+ inputSource: MouseEvent.MOZ_SOURCE_MOUSE,
+ isWidgetEventSynthesized: true });
+ synthesizeMouseAtCenter(target1, { type: "mousedown" });
+ synthesizeMouseAtCenter(target1, { type: "mouseup" });
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_1.html b/dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_1.html
new file mode 100644
index 0000000000..a02432f3b3
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_1.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1293174</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ setImplicitPointerCapture(true, loadSubFrame);
+ }
+ function loadSubFrame() {
+ runTestInNewWindow("bug1293174_implicit_pointer_capture_for_touch_1.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchmove");
+ sendTouchEvent(int_win, "target1", "touchmove");
+ sendTouchEvent(int_win, "target0", "touchmove");
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
+
diff --git a/dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_2.html b/dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_2.html
new file mode 100644
index 0000000000..2e5aaccccc
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1293174_implicit_pointer_capture_for_touch_2.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1293174</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ setImplicitPointerCapture(false, loadSubFrame);
+ }
+ function loadSubFrame() {
+ runTestInNewWindow("bug1293174_implicit_pointer_capture_for_touch_2.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchmove");
+ sendTouchEvent(int_win, "target1", "touchmove");
+ sendTouchEvent(int_win, "target0", "touchmove");
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
+
diff --git a/dom/events/test/pointerevents/test_bug1303704.html b/dom/events/test/pointerevents/test_bug1303704.html
new file mode 100644
index 0000000000..3fc1fb799a
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1303704.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1303704
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1303704</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ #scrollable {
+ height: 80px;
+ width: 200px;
+ overflow-y: scroll;
+ margin-bottom: 50px;
+ scroll-behavior: auto;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1303704">Mozilla Bug 1303704</a>
+<p id="display"></p>
+<a id="link1" href="http://www.google.com">Link 1</a>
+<div id="scrollable">
+<pre>
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+scroll
+</pre>
+</div>
+<script type="text/javascript">
+
+/** Test for Bug 1303704 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let link1 = window.document.getElementById("link1");
+ let mouseEvents = ["mousedown", "mouseup", "mousemove"];
+
+ link1.addEventListener("pointerdown", (e) => {
+ e.preventDefault();
+ is(e.defaultPrevented, true, "defaultPrevented should be true");
+ });
+
+ mouseEvents.forEach((elm, index, arr) => {
+ link1.addEventListener(elm, () => {
+ ok(false, "Should not receive " + elm + " after preventDefault on pointerdown");
+ });
+ });
+
+ link1.addEventListener("click", (e) => {
+ e.preventDefault();
+ });
+
+ synthesizeMouseAtCenter(link1, { type: "mousedown",
+ inputSource: MouseEvent.MOZ_SOURCE_MOUSE });
+ synthesizeMouseAtCenter(link1, { type: "mousemove",
+ inputSource: MouseEvent.MOZ_SOURCE_MOUSE });
+ synthesizeMouseAtCenter(link1, { type: "mouseup",
+ inputSource: MouseEvent.MOZ_SOURCE_MOUSE });
+
+ if (navigator.userAgent.includes("Android") ||
+ navigator.userAgent.includes("Mac") ||
+ SpecialPowers.Cc["@mozilla.org/gfx/info;1"].
+ getService(SpecialPowers.Ci.nsIGfxInfo).isHeadless) {
+ SimpleTest.finish();
+ return;
+ }
+
+ async function scrollTest() {
+ var scrollable = document.getElementById("scrollable");
+ scrollable.addEventListener('pointerdown', function(ev) {
+ ev.preventDefault();
+ }, true);
+ var rect = scrollable.getBoundingClientRect();
+ var offsetX = rect.width - 5;
+ var offsetY = rect.height - 5;
+ synthesizeMouse(scrollable, offsetX, offsetY,
+ { type: "mousedown",
+ inputSource: MouseEvent.MOZ_SOURCE_MOUSE });
+
+ synthesizeMouse(scrollable, offsetX, offsetY,
+ { type: "mousemove",
+ inputSource: MouseEvent.MOZ_SOURCE_MOUSE });
+
+ synthesizeMouse(scrollable, offsetX, offsetY,
+ { type: "mouseup",
+ inputSource: MouseEvent.MOZ_SOURCE_MOUSE });
+
+ await waitToClearOutAnyPotentialScrolls(window);
+
+ if (scrollable.scrollTop != 0) {
+ isnot(scrollable.scrollTop, 0,
+ "Scrollable element should have been scrolled.");
+ SimpleTest.finish();
+ } else {
+ setTimeout(scrollTest);
+ }
+ }
+
+ setTimeout(() => {
+ var scrollable = document.getElementById("scrollable");
+ is(scrollable.scrollTop, 0,
+ "Scrollable element shouldn't be scrolled initially");
+ scrollTest();
+ });
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true], ["general.smoothScroll", false]]}, runTests);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_bug1315862.html b/dom/events/test/pointerevents/test_bug1315862.html
new file mode 100644
index 0000000000..55f5690d5b
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1315862.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1315862
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1315862</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="content">
+ This is a test to check if pointer events are dispatched in the system group
+</p>
+<script type="text/javascript">
+
+/** Test for Bug 1315862 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let allPointerEvents = ["pointerdown", "pointerup", "pointercancel",
+ "pointermove", "pointerover", "pointerout",
+ "pointerenter", "pointerleave", "gotpointercapture",
+ "lostpointercapture"
+ ];
+ let content = document.getElementById('content');
+ let iframe = document.createElement('iframe');
+ let receivePointerEvents = false;
+ iframe.width = 50;
+ iframe.height = 50;
+ content.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML =
+ "<div style='width: 100%; height: 100%; border: 1px solid black;'></div>";
+
+ let target = iframe.contentDocument.body.firstChild;
+ allPointerEvents.forEach((event, idx, arr) => {
+ SpecialPowers.addSystemEventListener(target, event, () => {
+ ok(false, "Shouldn't dispatch " + event + " in the system group");
+ receivePointerEvents = true;
+ });
+ });
+ target.addEventListener("pointerdown", (e) => {
+ target.setPointerCapture(e.pointerId);
+ });
+ target.addEventListener("pointerup", () => {
+ is(receivePointerEvents, false, "Shouldn't dispatch pointer events in the system group");
+ SimpleTest.finish();
+ });
+ let source = MouseEvent.MOZ_SOURCE_MOUSE;
+ synthesizeMouse(target, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target, 5, 5, { type: "mousedown", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target, 5, 5, { type: "mouseup", inputSource: source },
+ iframe.contentWindow);
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_bug1323158.html b/dom/events/test/pointerevents/test_bug1323158.html
new file mode 100644
index 0000000000..5dbae4966d
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1323158.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1323158
+-->
+<head>
+ <meta charset="utf-8">
+ <title>This is a test to check if target and relatedTarget of mouse events are the same as pointer events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="content"></p>
+<script type="text/javascript">
+
+/** Test for Bug 1323158 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let content = document.getElementById('content');
+ let iframe = document.createElement('iframe');
+ iframe.width = 500;
+ iframe.height = 500;
+ content.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML =
+ "<br><div id='target0' style='width: 30px; height: 30px; background: black;'></div>" +
+ "<br><div id='target1' style='width: 30px; height: 30px; background: red;'></div>" +
+ "<br><div id='done' style='width: 30px; height: 30px; background: green;'></div>";
+
+ let target0 = iframe.contentDocument.getElementById("target0");
+ let target1 = iframe.contentDocument.getElementById("target1");
+ let done = iframe.contentDocument.getElementById("done");
+ let pointerBoundaryEvents = ["pointerover", "pointerenter", "pointerleave", "pointerout"];
+ let mouseBoundaryEvents = ["mouseover", "mouseenter", "mouseleave", "mouseout"];
+ let receivedPointerBoundaryEvents = {};
+ let mouseEvent2pointerEvent = {"mouseover": "pointerover",
+ "mouseenter": "pointerenter",
+ "mouseleave": "pointerleave",
+ "mouseout": "pointerout"
+ };
+
+ pointerBoundaryEvents.forEach((event) => {
+ target1.addEventListener(event, (e) => {
+ receivedPointerBoundaryEvents[event] = e;
+ }, {once: true});
+ });
+
+ let attributes = ["target", "relatedTarget"];
+ mouseBoundaryEvents.forEach((event) => {
+ target1.addEventListener(event, (e) => {
+ let correspondingPointerEv = receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]];
+ ok(correspondingPointerEv, "Should receive " + mouseEvent2pointerEvent[event] + " before " + e.type);
+ if (correspondingPointerEv) {
+ attributes.forEach((attr) => {
+ ok(correspondingPointerEv[attr] == e[attr],
+ attr + " of " + e.type + " should be the same as the correcponding pointer event expect " +
+ correspondingPointerEv[attr] + " got " + e[attr]);
+ });
+ }
+ receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]] = null;
+ }, {once: true});
+ });
+ target0.addEventListener("pointerdown", (e) => {
+ target1.setPointerCapture(e.pointerId);
+ });
+ done.addEventListener("mouseup", () => {
+ SimpleTest.finish();
+ });
+ let source = MouseEvent.MOZ_SOURCE_MOUSE;
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(done, 5, 5, { type: "mousedown", inputSource: source },
+ iframe.contentWindow);
+ synthesizeMouse(done, 5, 5, { type: "mouseup", inputSource: source },
+ iframe.contentWindow);
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_bug1403055.html b/dom/events/test/pointerevents/test_bug1403055.html
new file mode 100644
index 0000000000..a236899b0c
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1403055.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1403055
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1403055</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1403055">Mozilla Bug 1403055</a>
+<p id="display"></p>
+<div id="target0" style="width: 50px; height: 50px; background: green"></div>
+<div id="target1" style="width: 50px; height: 50px; background: red"></div>
+<div id="done" style="width: 50px; height: 50px; background: black"></div>
+<script type="text/javascript">
+/** Test for Bug 1403055 **/
+SimpleTest.waitForExplicitFinish();
+
+var target0 = window.document.getElementById("target0");
+var target1 = window.document.getElementById("target1");
+var done = window.document.getElementById("done");
+
+function withoutImplicitlyPointerCaptureForTouch() {
+ let target0_events = ["pointerover", "pointerenter", "pointerdown", "pointermove"];
+ let target1_events = ["pointerover", "pointerenter", "pointermove", "pointercancel", "pointerout", "pointerleave"];
+
+ target0_events.forEach((elem, index, arr) => {
+ target0.addEventListener(elem, (event) => {
+ is(event.type, target0_events[0], "receive " + event.type + " on target0");
+ target0_events = target0_events.filter(item => item !== event.type);
+ }, { once: true });
+ });
+
+ target1_events.forEach((elem, index, arr) => {
+ target1.addEventListener(elem, (event) => {
+ is(event.type, target1_events[0], "receive " + event.type + " on target1");
+ target1_events = target1_events.filter(item => item !== event.type);
+ }, { once: true });
+ });
+
+ done.addEventListener("mouseup", () => {
+ ok(target0_events.length == 0, " should receive " + target0_events + " on target0");
+ ok(target1_events.length == 0, " should receive " + target1_events + " on target1");
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.w3c_pointer_events.implicit_capture", true]]},
+ withImplicitlyPointerCaptureForTouch);
+ }, {once : true});
+
+ synthesizeTouch(target0, 5, 5, { type: "touchstart" });
+ synthesizeTouch(target0, 5, 5, { type: "touchmove" });
+ synthesizeTouch(target1, 5, 5, { type: "touchmove" });
+ synthesizeTouch(target1, 5, 5, { type: "touchcancel" });
+ synthesizeMouseAtCenter(done, { type: "mousedown" });
+ synthesizeMouseAtCenter(done, { type: "mouseup" });
+}
+
+function withImplicitlyPointerCaptureForTouch() {
+ let target0_events = ["pointerover", "pointerenter", "pointerdown", "pointermove", "pointercancel", "pointerout", "pointerleave"];
+
+ target0_events.forEach((elem, index, arr) => {
+ target0.addEventListener(elem, (event) => {
+ is(event.type, target0_events[0], "receive " + event.type + " on target0");
+ target0_events = target0_events.filter(item => item !== event.type);
+ }, { once: true });
+ });
+
+ done.addEventListener("mouseup", () => {
+ ok(target0_events.length == 0, " should receive " + target0_events + " on target0");
+ SimpleTest.finish();
+ }, {once : true});
+
+ synthesizeTouch(target0, 5, 5, { type: "touchstart" });
+ synthesizeTouch(target0, 5, 5, { type: "touchmove" });
+ synthesizeTouch(target1, 5, 5, { type: "touchmove" });
+ synthesizeTouch(target1, 5, 5, { type: "touchcancel" });
+ synthesizeMouseAtCenter(done, { type: "mousedown" });
+ synthesizeMouseAtCenter(done, { type: "mouseup" });
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.w3c_pointer_events.implicit_capture", false]]},
+ withoutImplicitlyPointerCaptureForTouch);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_bug1420589_1.html b/dom/events/test/pointerevents/test_bug1420589_1.html
new file mode 100644
index 0000000000..a3808ea061
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1420589_1.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1420589
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1420589</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1420589">Mozilla Bug 1420589</a>
+<p id="display"></p>
+<iframe id="iframe1" src="./bug_1420589_iframe1.html">
+</iframe>
+<iframe id="iframe2" src="./bug_1420589_iframe2.html">
+</iframe>
+<script type="text/javascript">
+/*
+ Test for Bug 1420589. This test synthesizes touch events with two points. The
+ first one hits iframe1 and the other hits iframe2.
+
+ We dispatch all touch events to the same document. We stop dispatching touch
+ events to a target if we can't find any ancestor document that is the same as
+ the document of the existing target. We check the points of the touch event in
+ reverse order. That means we choose the document of iframe2 as our targeted
+ document. We won't dispatch touch events to the document of iframe1 nor the
+ parent document of iframe1 and iframe2.
+
+ We dispatch pointer events to the hit targets even when there aren't in the
+ same document. This test expects that pointer events are dispatched to the div
+ element and the iframe document.
+*/
+SimpleTest.waitForExplicitFinish();
+
+var rx = 1;
+var ry = 1;
+var angle = 0;
+var force = 1;
+var modifiers = 0;
+var test1PointerId = 1;
+var test2PointerId = 2;
+
+function withoutImplicitlyPointerCaptureForTouch() {
+ let expectedEvents = [
+ // messages from the document of iframe1
+ "iframe1 pointerdown",
+ "iframe1 pointermove",
+ "iframe1 pointerup",
+
+ // messages from the document of iframe2
+ "iframe2 pointerdown",
+ "iframe2 pointermove",
+ "iframe2 pointerup",
+ "iframe2 touchstart",
+ "iframe2 touchmove",
+ "iframe2 touchend",
+ ];
+
+ window.addEventListener('message',function(e) {
+ ok(expectedEvents.includes(e.data), " don't expect " + e.data);
+ expectedEvents = expectedEvents.filter(item => item !== e.data);
+ if (e.data == "iframe2 touchend") {
+ ok(expectedEvents.length == 0, " expect " + expectedEvents);
+ SimpleTest.finish();
+ }
+ })
+
+ let iframe1 = document.getElementById('iframe1');
+ let iframe2 = document.getElementById('iframe2');
+
+ let rect1 = iframe1.getBoundingClientRect();
+ let rect2 = iframe2.getBoundingClientRect();
+
+ let left1 = rect1.left + 5;
+ let left2 = rect2.left + 5;
+
+ let top1 = rect1.top + 5;
+ let top2 = rect2.top + 5;
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.sendTouchEvent('touchstart', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+ utils.sendTouchEvent('touchmove', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+ utils.sendTouchEvent('touchend', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.w3c_pointer_events.implicit_capture", false]]},
+ withoutImplicitlyPointerCaptureForTouch);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_bug1420589_2.html b/dom/events/test/pointerevents/test_bug1420589_2.html
new file mode 100644
index 0000000000..9a8eff762a
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1420589_2.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1420589
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1420589</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1420589">Mozilla Bug 1420589</a>
+<p id="display"></p>
+<div id="div1" style="width: 50px; height: 50px; background: green"></div>
+<iframe id="iframe1" src="./bug_1420589_iframe1.html">
+</iframe>
+<script type="text/javascript">
+/*
+ Test for Bug 1420589. This test synthesizes touch events with two points. One
+ hits the div element on the document and the other hits the iframe element.
+
+ We dispatch all touch events to the same document. If we find any target that
+ is not in the same document of the existed target, we try to find the ancestor
+ document of the new target which is in the same as the existing target and
+ dispatch touch events to it. We check the points of the touch event in reverse
+ order. That means we only dispatch touch events to the document which contains
+ the div element in this test and expect the div element and iframe element
+ receive touch events.
+
+ We dispatch pointer events to the hit targets even when there aren't in the
+ same document. This test expects that pointer events are dispatched to the div
+ element and the iframe document.
+*/
+SimpleTest.waitForExplicitFinish();
+
+var rx = 1;
+var ry = 1;
+var angle = 0;
+var force = 1;
+var modifiers = 0;
+var test1PointerId = 1;
+var test2PointerId = 2;
+
+function withoutImplicitlyPointerCaptureForTouch() {
+ let expectedEvents = [
+ // messages from the document of iframe1
+ "iframe1 pointerdown",
+ "iframe1 pointermove",
+ "iframe1 pointerup",
+
+ // messages from the parent document
+ "iframe touchstart",
+ "iframe touchmove",
+ "iframe touchend",
+ "div1 pointerdown",
+ "div1 pointermove",
+ "div1 pointerup",
+ "div1 touchstart",
+ "div1 touchmove",
+ "div1 touchend",
+ ];
+
+ window.addEventListener('message',function(e) {
+ ok(expectedEvents.includes(e.data), " don't expect " + e.data);
+ expectedEvents = expectedEvents.filter(item => item !== e.data);
+ if (e.data == "div1 touchend") {
+ ok(expectedEvents.length == 0, " expect " + expectedEvents);
+ SimpleTest.finish();
+ }
+ })
+
+ let iframe1 = document.getElementById('iframe1');
+ let div1 = document.getElementById('div1');
+
+ let events = ["touchstart", "touchmove", "touchend", "pointerdown", "pointermove", "pointerup"];
+ events.forEach((event) => {
+ div1.addEventListener(event, (e) => {
+ postMessage("div1 " + e.type, "*");
+ }, { once: true });
+ iframe1.addEventListener(event, (e) => {
+ postMessage("iframe " + e.type, "*");
+ }, { once: true });
+ });
+
+ let rect1 = iframe1.getBoundingClientRect();
+ let rect2 = div1.getBoundingClientRect();
+
+ let left1 = rect1.left + 5;
+ let left2 = rect2.left + 5;
+
+ let top1 = rect1.top + 5;
+ let top2 = rect2.top + 5;
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.sendTouchEvent('touchstart', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+
+ // Move the touch pointers so that we dispatch all of them to content.
+ left1++;
+ left2++;
+ utils.sendTouchEvent('touchmove', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+ utils.sendTouchEvent('touchend', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.w3c_pointer_events.implicit_capture", false]]},
+ withoutImplicitlyPointerCaptureForTouch);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_bug1420589_3.html b/dom/events/test/pointerevents/test_bug1420589_3.html
new file mode 100644
index 0000000000..69a2f03bc3
--- /dev/null
+++ b/dom/events/test/pointerevents/test_bug1420589_3.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1420589
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1420589</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1420589">Mozilla Bug 1420589</a>
+<p id="display"></p>
+<div id="div1" style="width: 50px; height: 50px; background: green"></div>
+<iframe id="iframe1" src="./bug_1420589_iframe1.html">
+</iframe>
+<script type="text/javascript">
+/*
+ Test for Bug 1420589. This test is similar to test_bug1420589_2.html but the
+ first touch point hit the div element and the second point hits the iframe.
+
+ We stop dispatching touch events to a target when we can't find any ancestor
+ document that is the same as the document of the existing target. This test
+ expects that we only dispatch touch events to the iframe document.
+
+ We dispatch pointer events to the hit targets even when there aren't in the
+ same document. This test expects that pointer events are dispatched to the div
+ element and the iframe document.
+*/
+SimpleTest.waitForExplicitFinish();
+
+var rx = 1;
+var ry = 1;
+var angle = 0;
+var force = 1;
+var modifiers = 0;
+var test1PointerId = 1;
+var test2PointerId = 2;
+
+function withoutImplicitlyPointerCaptureForTouch() {
+ let expectedEvents = [
+ // messages from the document of iframe1
+ "iframe1 pointerdown",
+ "iframe1 pointermove",
+ "iframe1 pointerup",
+ "iframe1 touchstart",
+ "iframe1 touchmove",
+ "iframe1 touchend",
+
+ // messages from the parent document
+ "div1 pointerdown",
+ "div1 pointermove",
+ "div1 pointerup",
+ ];
+
+ window.addEventListener('message',function(e) {
+ ok(expectedEvents.includes(e.data), " don't expect " + e.data);
+ expectedEvents = expectedEvents.filter(item => item !== e.data);
+ if (e.data == "iframe1 touchend") {
+ ok(expectedEvents.length == 0, " expect " + expectedEvents);
+ SimpleTest.finish();
+ }
+ })
+
+ let iframe1 = document.getElementById('iframe1');
+ let div1 = document.getElementById('div1');
+
+ let events = ["touchstart", "touchmove", "touchend", "pointerdown", "pointermove", "pointerup"];
+ events.forEach((event) => {
+ div1.addEventListener(event, (e) => {
+ postMessage("div1 " + e.type, "*");
+ }, { once: true });
+ iframe1.addEventListener(event, (e) => {
+ postMessage("iframe " + e.type, "*");
+ }, { once: true });
+ });
+
+ let rect1 = div1.getBoundingClientRect();
+ let rect2 = iframe1.getBoundingClientRect();
+
+ let left1 = rect1.left + 5;
+ let left2 = rect2.left + 5;
+
+ let top1 = rect1.top + 5;
+ let top2 = rect2.top + 5;
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.sendTouchEvent('touchstart', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+
+ // Move the touch pointers so that we dispatch all of them to content.
+ left1++;
+ left2++;
+ utils.sendTouchEvent('touchmove', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+ utils.sendTouchEvent('touchend', [test1PointerId, test2PointerId],
+ [left1, left2], [top1, top2], [rx, rx], [ry, ry],
+ [angle, angle], [force, force], modifiers);
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.w3c_pointer_events.implicit_capture", false]]},
+ withoutImplicitlyPointerCaptureForTouch);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_getCoalescedEvents.html b/dom/events/test/pointerevents/test_getCoalescedEvents.html
new file mode 100644
index 0000000000..7c4f9ad5be
--- /dev/null
+++ b/dom/events/test/pointerevents/test_getCoalescedEvents.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1303957
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1303957</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1303957">Mozilla Bug 1303957</a>
+<p id="display"></p>
+<div id="target0" style="width: 50px; height: 50px; background: green"></div>
+<script type="text/javascript">
+/** Test for Bug 1303957 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let target0 = window.document.getElementById("target0");
+ let utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.advanceTimeAndRefresh(0);
+
+ SimpleTest.executeSoon(() => {
+ // Flush all pending mouse events before synthesizing events.
+
+ target0.addEventListener("pointermove", (ev) => {
+ let length = ev.getCoalescedEvents().length;
+ ok(length >= 1, "Coalesced events should >= 1, got " + length);
+
+ let rect = target0.getBoundingClientRect();
+ let prevOffsetX = 0;
+ let prevOffsetY = 0;
+
+ for (let i = 0; i < length; ++i) {
+ let coalescedEvent = ev.getCoalescedEvents()[i];
+ isnot(coalescedEvent.timeStamp, 0, "getCoalescedEvents()[" + i + "].timeStamp");
+ is(coalescedEvent.pointerId, ev.pointerId, "getCoalescedEvents()[" + i + "].pointerId");
+ is(coalescedEvent.pointerType, ev.pointerType, "getCoalescedEvents()[" + i + "].pointerType");
+ is(coalescedEvent.isPrimary, ev.isPrimary, "getCoalescedEvents()[" + i + "].isPrimary");
+ is(coalescedEvent.target, ev.target, "getCoalescedEvents()[" + i + "].target");
+ is(coalescedEvent.currentTarget, null, "getCoalescedEvents()[" + i + "].currentTarget");
+ is(coalescedEvent.eventPhase, Event.NONE, "getCoalescedEvents()[" + i + "].eventPhase");
+ is(coalescedEvent.cancelable, false, "getCoalescedEvents()[" + i + "].cancelable");
+ is(coalescedEvent.bubbles, false, "getCoalescedEvents()[" + i + "].bubbles");
+
+ ok(coalescedEvent.offsetX >= prevOffsetX, "getCoalescedEvents()[" + i + "].offsetX = " + coalescedEvent.offsetX);
+ ok(coalescedEvent.offsetX == 5 || coalescedEvent.offsetX == 10 ||
+ coalescedEvent.offsetX == 15 || coalescedEvent.offsetX == 20, "expected offsetX");
+
+ ok(coalescedEvent.offsetY >= prevOffsetY, "getCoalescedEvents()[" + i + "].offsetY = " + coalescedEvent.offsetY);
+ ok(coalescedEvent.offsetY == 5 || coalescedEvent.offsetY == 10 ||
+ coalescedEvent.offsetY == 15 || coalescedEvent.offsetY == 20, "expected offsetY");
+
+ prevOffsetX = coalescedEvent.offsetX;
+ prevOffsetY = coalescedEvent.offsetY;
+
+ let x = rect.left + prevOffsetX;
+ let y = rect.top + prevOffsetY;
+ // coordinates may change slightly due to rounding
+ ok((coalescedEvent.clientX <= x+2) && (coalescedEvent.clientX >= x-2), "getCoalescedEvents()[" + i + "].clientX");
+ ok((coalescedEvent.clientY <= y+2) && (coalescedEvent.clientY >= y-2), "getCoalescedEvents()[" + i + "].clientY");
+ }
+ }, { once: true });
+
+ target0.addEventListener("pointerup", (ev) => {
+ utils.restoreNormalRefresh();
+ SimpleTest.finish();
+ }, { once: true });
+
+ synthesizeNativeMouseMove(target0, 5, 5, () => {
+ synthesizeNativeMouseMove(target0, 10, 10, () => {
+ synthesizeNativeMouseMove(target0, 15, 15, () => {
+ synthesizeNativeMouseMove(target0, 20, 20, () => {
+ synthesizeNativeMouseClick(target0, 20, 20);
+ });
+ });
+ });
+ });
+ });
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.event.coalesce_mouse_move", true]]}, runTests);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_multiple_touches.html b/dom/events/test/pointerevents/test_multiple_touches.html
new file mode 100644
index 0000000000..89b476b26d
--- /dev/null
+++ b/dom/events/test/pointerevents/test_multiple_touches.html
@@ -0,0 +1,189 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Multiple Touches</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="target0" style="width: 100px; height: 100px; background: green"></div>
+<div id="target1" style="width: 100px; height: 100px; background: red"></div>
+<script type="text/javascript">
+// TODO: We should probably make EventUtils.js to support multiple touch.
+// Currently the use case is simple, so we just add support here.
+// Once we have more use cases, we could come out a more generic way to
+// support it.
+var touches = {
+ ids: [],
+ lefts: [],
+ tops: [],
+ rxs: [],
+ rys: [],
+ angles: [],
+ forces: [],
+};
+
+function synthesizeTouchEvent(aType, aIds, aLefts, aTops, aRxs, aRys, aAngles, aForces) {
+ var utils = _getDOMWindowUtils(window);
+ if (!utils) {
+ ok(false, "unable to get nsIDOMWindowUtils");
+ return;
+ }
+
+ utils.sendTouchEvent(aType, aIds, aLefts, aTops, aRxs, aRys,
+ aAngles, aForces, 0 /* modifiers */);
+}
+
+function synthesizeTouchStart(aTarget, aId, aOffsetX, aOffsetY) {
+ if (touches.ids.some((aElem) => { return aElem === aId; })) {
+ ok(false, `touch with id=${aTouch.id} is already registered`);
+ return;
+ }
+
+ let rect = aTarget.getBoundingClientRect();
+ touches.ids.push(aId);
+ touches.lefts.push(rect.left + aOffsetX);
+ touches.tops.push(rect.top + aOffsetY);
+ touches.rxs.push(1);
+ touches.rys.push(1);
+ touches.angles.push(0);
+ touches.forces.push(1);
+
+ synthesizeTouchEvent("touchstart", touches.ids, touches.lefts, touches.tops,
+ touches.rxs, touches.rys, touches.angles, touches.forces);
+}
+
+function synthesizeTouchEnd(aTarget, aId, aOffsetX, aOffsetY) {
+ let index = touches.ids.indexOf(aId);
+ if (-1 === index) {
+ ok(false, `touch with id=${aTouch.id} isn't registered`);
+ return;
+ }
+
+ let rect = aTarget.getBoundingClientRect();
+ touches.ids.splice(index, 1);
+ touches.lefts.splice(index, 1);
+ touches.tops.splice(index, 1);
+ touches.rxs.splice(index, 1);
+ touches.rys.splice(index, 1);
+ touches.angles.splice(index, 1);
+ touches.forces.splice(index, 1);
+
+ synthesizeTouchEvent("touchend", [aId], [rect.left + aOffsetX], [rect.top + aOffsetY],
+ [1], [1], [0], [1]);
+}
+
+function synthesizeTouchMove(aTarget, aId, aOffsetX, aOffsetY) {
+ let index = touches.ids.indexOf(aId);
+ if (-1 === index) {
+ ok(false, `touch with id=${aTouch.id} isn't registered`);
+ return;
+ }
+
+ let rect = aTarget.getBoundingClientRect();
+ touches.lefts[index] = rect.left + aOffsetX;
+ touches.tops[index] = rect.top + aOffsetY;
+
+ synthesizeTouchEvent("touchmove", touches.ids, touches.lefts, touches.tops,
+ touches.rxs, touches.rys, touches.angles, touches.forces);
+}
+
+var target0 = document.getElementById("target0");
+var target1 = document.getElementById("target1");
+
+function WaitExpectedEvents(aListenEvents, aExpectedEvents, aEventGenerator) {
+ let promise = new Promise(function(aResolve) {
+ let index = 0;
+ let checkReceivedEvents = function(aEvent) {
+ if (aExpectedEvents.length === 0) {
+ ok(false, `receive unexpected ${aEvent.type} event from ${aEvent.target}`);
+ return;
+ }
+ index++;
+ let expectedResult = aExpectedEvents.shift();
+ isDeeply(expectedResult, [aEvent.target, aEvent.type], `${index}. expect receive ${expectedResult[1]} event from ${expectedResult[0]}`);
+ if (aExpectedEvents.length === 0) {
+ // Wait a bit to see if there is any additional unexpected event fired.
+ setTimeout(function() {
+ // Clean up
+ aListenEvents.forEach((aElem) => {
+ target0.removeEventListener(aElem, checkReceivedEvents);
+ target1.removeEventListener(aElem, checkReceivedEvents);
+ });
+ aResolve();
+ }, 0);
+ }
+ };
+
+ aListenEvents.forEach((aElem) => {
+ target0.addEventListener(aElem, checkReceivedEvents);
+ target1.addEventListener(aElem, checkReceivedEvents);
+ });
+ });
+
+ aEventGenerator();
+
+ return promise;
+}
+
+add_task(async function setup() {
+ await SimpleTest.promiseFocus();
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.w3c_pointer_events.enabled", true],
+ ["dom.w3c_pointer_events.implicit_capture", false]]
+ });
+});
+
+// Test for bug 1521082
+add_task(async function ShouldNotSendDuplicatedPointerDown() {
+ return WaitExpectedEvents(
+ ["pointerup", "pointerdown"],
+ [ // [event target, event type]
+ [target0, "pointerdown"],
+ [target1, "pointerdown"],
+ [target1, "pointerup"],
+ [target0, "pointerup"],
+ ],
+ function() {
+ var defaultId = SpecialPowers.Ci.nsIDOMWindowUtils.DEFAULT_TOUCH_POINTER_ID;
+ synthesizeTouchStart(target0, defaultId, 10, 10);
+ synthesizeTouchStart(target1, defaultId + 1, 10, 10);
+ synthesizeTouchEnd(target1, defaultId + 1, 10, 10);
+ synthesizeTouchEnd(target0, defaultId, 10, 10);
+ }
+ );
+});
+
+// Test for bug 1323400
+add_task(async function ShouldNotSendDuplicatedPointerMove() {
+ return WaitExpectedEvents(
+ ["pointerup", "pointerdown","pointermove"],
+ [ // [event target, event type]
+ [target0, "pointerdown"],
+ [target1, "pointerdown"],
+ // The first pointermove should not be suppressed.
+ [target0, "pointermove"],
+ [target1, "pointermove"],
+ // Should receive only one pointer event for target 1.
+ [target1, "pointermove"],
+ [target1, "pointerup"],
+ [target0, "pointerup"],
+ ],
+ function() {
+ var defaultId = SpecialPowers.Ci.nsIDOMWindowUtils.DEFAULT_TOUCH_POINTER_ID;
+ synthesizeTouchStart(target0, defaultId, 10, 10);
+ synthesizeTouchStart(target1, defaultId + 1, 10, 10);
+ synthesizeTouchMove(target1, defaultId + 1, 11, 11);
+ synthesizeTouchMove(target1, defaultId + 1, 12, 12);
+ synthesizeTouchEnd(target1, defaultId + 1, 10, 10);
+ synthesizeTouchEnd(target0, defaultId, 10, 10);
+ }
+ );
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_pointercapture_remove_iframe.html b/dom/events/test/pointerevents/test_pointercapture_remove_iframe.html
new file mode 100644
index 0000000000..3ccf3292f3
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointercapture_remove_iframe.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1686037
+-->
+<head>
+<title>Bug 1686037</title>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<style>
+#target {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+iframe {
+ width: 400px;
+ height: 300px;
+ border: 1px solid blue;
+}
+</style>
+</head>
+<body>
+<a target="_blank"href="https://bugzilla.mozilla.org/show_bug.cgi?id=1686037">Mozilla Bug 1686037</a>
+<div id="target"></div>
+<iframe srcdoc="<div style='width: 100px; height: 100px; background-color: blue;'></div>"></iframe>
+
+<pre id="test">
+<script type="text/javascript">
+/**
+ * Test for Bug 1686037
+ */
+function waitForEvent(aTarget, aEventName, aCallback = null) {
+ return new Promise((aResolve) => {
+ aTarget.addEventListener(aEventName, async (e) => {
+ ok(true, `got ${e.type} event on ${e.target}, pointerid: ${e.pointerId}`);
+ if (aCallback) {
+ await aCallback(e);
+ }
+ aResolve();
+ }, { once: true });
+ });
+}
+
+function waitForPointerDownAndSetPointerCapture(aTarget) {
+ return waitForEvent(aTarget, "pointerdown", async (event) => {
+ return new Promise((aResolve) => {
+ aTarget.addEventListener("gotpointercapture", (e) => {
+ ok(true, `got ${e.type} event on ${e.target}, pointerid: ${e.pointerId}`);
+ aResolve();
+ }, { once: true });
+
+ aTarget.setPointerCapture(event.pointerId);
+ });
+ });
+}
+
+add_task(async function test_remove_iframe_after_pointer_capture() {
+ await SimpleTest.promiseFocus();
+
+ let iframe = document.querySelector("iframe");
+ let iframeWin = iframe.contentWindow;
+ let targetInIframe = iframe.contentDocument.querySelector("div");
+ let promise = Promise.all([
+ waitForPointerDownAndSetPointerCapture(targetInIframe),
+ waitForEvent(targetInIframe, "pointermove")
+ ]);
+ synthesizeTouch(targetInIframe, 10, 10, { type: "touchstart", id: 10 }, iframeWin);
+ synthesizeTouch(targetInIframe, 10, 10, { type: "touchmove", id: 10 }, iframeWin);
+ await promise;
+
+ // Intentionally not synthesize touchend event to not trigger implicit releasing
+ // pointer capture. And iframe removal should trigger pointer capture clean up.
+ iframe.remove();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_pointercapture_xorigin_iframe.html b/dom/events/test/pointerevents/test_pointercapture_xorigin_iframe.html
new file mode 100644
index 0000000000..46dcd10390
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointercapture_xorigin_iframe.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test for pointer capture</title>
+<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="#">Test for pointer capture</a>
+<div id="content"></div>
+<pre id="test">
+<script type="application/javascript">
+/**
+ * Pointer capture tests.
+ **/
+
+SimpleTest.waitForExplicitFinish();
+
+let gTestFiles = [
+ "file_pointercapture_xorigin_iframe.html",
+ "file_pointercapture_xorigin_iframe_pointerlock.html",
+];
+
+let gTestWindow = null;
+let gTestIndex = 0;
+
+SpecialPowers.pushPrefEnv({"set": [
+ // This will make dispatched event going through parent process.
+ ["test.events.async.enabled", true]
+]}, nextTest);
+
+function nextTest() {
+ if (gTestWindow) {
+ gTestWindow.close();
+ }
+ SimpleTest.waitForFocus(runNextTest);
+}
+
+function runNextTest() {
+ if (gTestIndex < gTestFiles.length) {
+ let file = gTestFiles[gTestIndex];
+ gTestIndex++;
+
+ info(`Testing ${file}`);
+ gTestWindow = window.open(file, "", "width=500,height=500");
+ } else {
+ SimpleTest.finish();
+ }
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html b/dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html
new file mode 100644
index 0000000000..535fcdec43
--- /dev/null
+++ b/dom/events/test/pointerevents/test_remove_frame_when_got_pointer_capture.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering popup by pointer events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="content">
+</p>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ let content = document.getElementById('content');
+ let iframe = document.createElement('iframe');
+ iframe.width = 200;
+ iframe.height = 200;
+ content.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML =
+ "<div id='div1' style='width: 50px; height: 50px; background: green'></div>" +
+ "<div id='div2' style='width: 50px; height: 50px; background: red'></div>";
+
+ let div1 = iframe.contentDocument.getElementById("div1");
+ let div2 = iframe.contentDocument.getElementById("div2");
+ let divEvents = [
+ "pointerdown",
+ "gotpointercapture",
+ "pointermove",
+ "pointerup",
+ "lostpointercapture",
+ "mousedown",
+ "mousemove",
+ "mouseup",
+ ];
+
+ let documentEvents = [
+ "pointerdown",
+ "pointermove",
+ "pointerup",
+ "mousedown",
+ "mousemove",
+ "mouseup",
+ ];
+
+ divEvents.forEach((event) => {
+ div1.addEventListener(event, (e) => {
+ ok(divEvents.includes(e.type), " don't expect " + e.type);
+ divEvents = divEvents.filter(item => item !== e.type);
+ }, { once: true });
+ });
+
+ documentEvents.forEach((event) => {
+ iframe.contentDocument.addEventListener(event, (e) => {
+ is(e.target, div1, e.type + " should be dispatched to div1");
+ }, { once: true });
+ });
+
+ div1.addEventListener("pointerdown", (e) => {
+ div1.setPointerCapture(e.pointerId);
+ });
+
+ div1.addEventListener("gotpointercapture", (e) => {
+ div1.style.display = "none";
+ });
+
+ info("Tests for mouseup");
+ synthesizeMouseAtCenter(div1, {type: "mousedown"}, iframe.contentWindow);
+ synthesizeMouseAtCenter(div2, {type: "mousemove"}, iframe.contentWindow);
+ synthesizeMouseAtCenter(div2, {type: "mouseup"}, iframe.contentWindow);
+
+ ok(divEvents.length == 0, " expect " + divEvents);
+
+ divEvents = [
+ "pointerdown",
+ "gotpointercapture",
+ "pointermove",
+ "pointerup",
+ "lostpointercapture",
+ "touchstart",
+ "touchmove",
+ "touchend",
+ ];
+
+ documentEvents = [
+ "pointerdown",
+ "pointermove",
+ "pointerup",
+ "touchstart",
+ "touchmove",
+ "touchend",
+ ];
+ divEvents.forEach((event) => {
+ div1.addEventListener(event, (e) => {
+ ok(divEvents.includes(e.type), " don't expect " + e.type);
+ divEvents = divEvents.filter(item => item !== e.type);
+ }, { once: true });
+ });
+
+ documentEvents.forEach((event) => {
+ iframe.contentDocument.addEventListener(event, (e) => {
+ is(e.target, div1, e.type + " should be dispatched to div1");
+ }, { once: true });
+ });
+
+ info("Tests for touchend");
+ div1.style.display = "block";
+ synthesizeMouseAtCenter(div1, {type: "mousemove"}, iframe.contentWindow);
+ synthesizeTouch(div1, 5, 5, { type: "touchstart" }, iframe.contentWindow);
+ synthesizeTouch(div2, 5, 5, { type: "touchmove" }, iframe.contentWindow);
+ synthesizeTouch(div2, 5, 5, { type: "touchend" }, iframe.contentWindow);
+
+ ok(divEvents.length == 0, " expect " + divEvents);
+
+ divEvents = [
+ "pointerdown",
+ "gotpointercapture",
+ "pointermove",
+ "pointercancel",
+ "lostpointercapture",
+ "touchstart",
+ "touchmove",
+ "touchcancel",
+ ];
+
+ documentEvents = [
+ "pointerdown",
+ "pointermove",
+ "pointercancel",
+ "touchstart",
+ "touchmove",
+ "touchcancel",
+ ];
+ divEvents.forEach((event) => {
+ div1.addEventListener(event, (e) => {
+ ok(divEvents.includes(e.type), " don't expect " + e.type);
+ divEvents = divEvents.filter(item => item !== e.type);
+ }, { once: true });
+ });
+
+ documentEvents.forEach((event) => {
+ iframe.contentDocument.addEventListener(event, (e) => {
+ is(e.target, div1, e.type + " should be dispatched to div1");
+ }, { once: true });
+ });
+
+ info("Tests for touchcancel");
+ div1.style.display = "block";
+ synthesizeMouseAtCenter(div1, {type: "mousemove"}, iframe.contentWindow);
+ synthesizeTouch(div1, 5, 5, { type: "touchstart" }, iframe.contentWindow);
+ synthesizeTouch(div2, 5, 5, { type: "touchmove" }, iframe.contentWindow);
+ synthesizeTouch(div2, 5, 5, { type: "touchcancel" }, iframe.contentWindow);
+
+ ok(divEvents.length == 0, " expect " + divEvents);
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({
+ "set": [["dom.w3c_pointer_events.enabled", true]]
+ }, startTest);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html
new file mode 100644
index 0000000000..3484e87f73
--- /dev/null
+++ b/dom/events/test/pointerevents/test_trigger_fullscreen_by_pointer_events.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering Fullscreen by pointer events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ let win = window.open("file_test_trigger_fullscreen.html", "_blank");
+ win.addEventListener("load", () => {
+ let target = win.document.getElementById("target");
+ target.addEventListener("pointerdown", () => {
+ target.requestFullscreen();
+ target.addEventListener("pointerdown", () => {
+ win.document.exitFullscreen();
+ }, {once: true});
+ }, {once: true});
+
+ win.document.addEventListener("fullscreenchange", () => {
+ if (win.document.fullscreenElement) {
+ is(win.document.fullscreenElement, target, "fullscreenElement should be the div element");
+ // synthesize mouse events to generate pointer events and leave full screen.
+ synthesizeMouseAtCenter(target, { type: "mousedown" }, win);
+ synthesizeMouseAtCenter(target, { type: "mouseup" }, win);
+ } else {
+ win.close();
+ SimpleTest.finish();
+ }
+ });
+ // Make sure our window is focused before starting the test
+ SimpleTest.waitForFocus(() => {
+ // synthesize mouse events to generate pointer events and enter full screen.
+ synthesizeMouseAtCenter(target, { type: "mousedown" }, win);
+ synthesizeMouseAtCenter(target, { type: "mouseup" }, win);
+ }, win);
+ });
+}
+
+SimpleTest.waitForFocus(() => {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["full-screen-api.allow-trusted-requests-only", false],
+ ["dom.w3c_pointer_events.enabled", true]
+ ]
+ }, startTest);
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_attributes_hoverable_pointers-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_attributes_hoverable_pointers-manual.html
new file mode 100644
index 0000000000..557ee80c4f
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_attributes_hoverable_pointers-manual.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Test pointerevent attributes for hoverable pointers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_attributes_hoverable_pointers-manual.html");
+ }
+ function executeTest(int_win) {
+ let iframeWin = int_win.document.getElementById("innerFrame").contentWindow;
+ // synthesize mouse events with input source = mouse
+ sendMouseEvent(int_win, "square1", "mousemove", {button:-1});
+ sendMouseEvent(int_win, "square1", "mousedown");
+ sendMouseEvent(int_win, "square1", "mouseup");
+ sendMouseEvent(int_win, "square1", "mousemove", {button:-1,
+ offsetX:-1,
+ offsetY:-1});
+ sendMouseEvent(iframeWin, "square2", "mousemove", {button:-1});
+ sendMouseEvent(iframeWin, "square2", "mousedown");
+ sendMouseEvent(iframeWin, "square2", "mouseup");
+ sendMouseEvent(iframeWin, "square2", "mousemove", {button:-1,
+ offsetX:-1,
+ offsetY:-1});
+ // synthesize mouse events with input source = pen
+ let inputPen = MouseEvent.MOZ_SOURCE_PEN;
+ sendMouseEvent(int_win, "square1", "mousemove", {button:-1,
+ inputSource: inputPen});
+ sendMouseEvent(int_win, "square1", "mousedown", {inputSource:inputPen});
+ sendMouseEvent(int_win, "square1", "mouseup", {inputSource:inputPen});
+ sendMouseEvent(int_win, "square1", "mousemove", {button:-1,
+ offsetX:-1,
+ offsetY:-1,
+ inputSource:inputPen});
+ sendMouseEvent(iframeWin, "square2", "mousemove", {button:-1,
+ inputSource:inputPen});
+ sendMouseEvent(iframeWin, "square2", "mousedown", {inputSource:inputPen});
+ sendMouseEvent(iframeWin, "square2", "mouseup", {inputSource:inputPen});
+ sendMouseEvent(iframeWin, "square2", "mousemove", {button:-1,
+ offsetX:-1,
+ offsetY:-1,
+ inputSource:inputPen});
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_attributes_nohover_pointers-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_attributes_nohover_pointers-manual.html
new file mode 100644
index 0000000000..f9fde4f92f
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_attributes_nohover_pointers-manual.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Test pointerevent attributes for non-hoverable pointers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_attributes_nohover_pointers-manual.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "square1", "touchstart");
+ sendTouchEvent(int_win, "square1", "touchend");
+ let iframe = int_win.document.getElementById("innerFrame");
+ sendTouchEvent(iframe.contentWindow, "square2", "touchstart");
+ sendTouchEvent(iframe.contentWindow, "square2", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_boundary_events_in_capturing-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_boundary_events_in_capturing-manual.html
new file mode 100644
index 0000000000..24aeb6d9a6
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_boundary_events_in_capturing-manual.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>W3C pointerevent_boundary_events_in_capturing-manual.html in Mochitest form</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_boundary_events_in_capturing-manual.html", true);
+ }
+ function executeTest(int_win) {
+ sendMouseEvent(int_win, "target0", "mousemove");
+ sendMouseEvent(int_win, "target0", "mousedown");
+ sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
+ sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
+ sendMouseEvent(int_win, "target0", "mouseup");
+
+ window.addEventListener("message", function(aEvent) {
+ if (aEvent.data == "Test Touch") {
+ // Synthesize touch events to run this test.
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchmove", {offsetX: 10});
+ sendTouchEvent(int_win, "target0", "touchmove", {offsetX: 15});
+ sendTouchEvent(int_win, "target0", "touchmove", {offsetX: 20});
+ sendTouchEvent(int_win, "target0", "touchend");
+ window.postMessage("Test Pen", "*");
+ } else if (aEvent.data == "Test Pen") {
+ // Synthesize pen events to run this test.
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
+ sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ }
+ });
+ window.postMessage("Test Touch", "*");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_change-touch-action-onpointerdown_touch-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_change-touch-action-onpointerdown_touch-manual.html
new file mode 100644
index 0000000000..f95b16c850
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_change-touch-action-onpointerdown_touch-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("pointerevent_change-touch-action-onpointerdown_touch-manual.html");
+ }
+ function executeTest(int_win) {
+ const WM_VSCROLL = 0x0115;
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchmove");
+ sendTouchEvent(int_win, "target0", "touchend");
+
+ // NOTE: This testcase is about that modifying touch-action during a
+ // pointerdown callback "should not" affect the gesture detection of the
+ // touch session started by the pointerdown. That is, a scroll should
+ // still fired by gesture detection, instead of launching by our own.
+ var utils = _getDOMWindowUtils(int_win);
+ var target0 = int_win.document.getElementById("target0");
+ utils.sendNativeMouseScrollEvent(target0.getBoundingClientRect().left + 5,
+ target0.getBoundingClientRect().top + 5,
+ WM_VSCROLL, 10, 10, 0, 0, 0, target0);
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_constructor.html b/dom/events/test/pointerevents/test_wpt_pointerevent_constructor.html
new file mode 100644
index 0000000000..058e32a967
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_constructor.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_constructor.html");
+ }
+ function executeTest(int_win) {
+ // Function should be, but can be empty
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_drag_interaction-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_drag_interaction-manual.html
new file mode 100644
index 0000000000..a05ee9557a
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_drag_interaction-manual.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1669673
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1669673</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/html/pointerevent_drag_interaction-manual.html");
+ }
+ async function executeTest(int_win) {
+ info("executeTest");
+ // DndWithoutCapture
+ await doDragAndDrop(int_win, "target0", "target1");
+ // DndWithCapture
+ await doDragAndDrop(int_win, "target0", "target1");
+ // DndWithCaptureMouse
+ await doDragAndDrop(int_win, "target0", "target1");
+ // DndPrevented
+ await doDragAndDrop(int_win, "target0", "target1", {
+ expectCancelDragStart: true,
+ // Move mouse to target1.
+ stepY: 33
+ });
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_movementxy-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_movementxy-manual.html
new file mode 100644
index 0000000000..3059f868b7
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_movementxy-manual.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1399740
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1399740</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerlock/pointerevent_movementxy-manual.html");
+ }
+ function executeTest(int_win) {
+ let box1 = int_win.document.getElementById("box1");
+ let box2 = int_win.document.getElementById("box2");
+ let rect1 = box1.getBoundingClientRect();
+ let rect2 = box2.getBoundingClientRect();
+ let offsetX = rect1.left + rect1.width / 2;
+ let offsetY = rect1.top + rect1.height / 2;
+ let stepX = (rect2.left + rect2.width / 2 - offsetX) / 10;
+ let stepY = (rect2.top + rect2.height / 2 - offsetY) / 10;
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+ for (var i = 0; i < 10; ++i) {
+ offsetX += stepX;
+ offsetY += stepY;
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+ }
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+
+ offsetX = rect1.left + rect1.width / 2;
+ offsetY = rect1.top + rect1.height / 2;
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+ for (var i = 0; i < 10; ++i) {
+ offsetX += stepX;
+ offsetY += stepY;
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+ }
+ sendMouseEventAtPoint(int_win, offsetX, offsetY, "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_multiple_primary_pointers_boundary_events-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_multiple_primary_pointers_boundary_events-manual.html
new file mode 100644
index 0000000000..825e23857f
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_multiple_primary_pointers_boundary_events-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_multiple_primary_pointers_boundary_events-manual.html");
+ }
+ function executeTest(int_win) {
+ sendMouseEvent(int_win, "target0", "mousemove");
+ sendTouchEvent(int_win, "target1", "touchstart");
+ sendTouchEvent(int_win, "target1", "touchend");
+ sendMouseEvent(int_win, "target0", "mousemove");
+ sendMouseEvent(int_win, "done", "mousedown");
+ sendMouseEvent(int_win, "done", "mouseup");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_pointerId_scope-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerId_scope-manual.html
new file mode 100644
index 0000000000..f52bf7fc20
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerId_scope-manual.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_pointerId_scope-manual.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_pointercancel_touch-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_pointercancel_touch-manual.html
new file mode 100644
index 0000000000..0adba4f756
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_pointercancel_touch-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_pointercancel_touch-manual.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchcancel");
+
+ // Need a touchend event to terminated the test gracefully.
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_after_pointercancel_touch-manual.html
new file mode 100644
index 0000000000..53c897bcd0
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_after_pointercancel_touch-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_pointerleave_after_pointercancel_touch-manual.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchcancel");
+
+ // Need a touchend event to terminated the test gracefully.
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_pen-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_pen-manual.html
new file mode 100644
index 0000000000..e4904780f6
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerleave_pen-manual.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_pointerleave_pen-manual.html");
+ }
+ function executeTest(int_win) {
+ sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousecancel", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_after_pointercancel_touch-manual.html
new file mode 100644
index 0000000000..53cf765fb6
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_after_pointercancel_touch-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_pointerout_after_pointercancel_touch-manual.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchcancel");
+
+ // Need a touchend event to terminated the test gracefully.
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_pen-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_pen-manual.html
new file mode 100644
index 0000000000..6b41f6492b
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_pointerout_pen-manual.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_pointerout_pen-manual.html");
+ }
+ function executeTest(int_win) {
+ sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousecancel", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_events_to_original_target-manual.html
new file mode 100644
index 0000000000..92d8be52f0
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_events_to_original_target-manual.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html");
+ }
+ function executeTest(int_win) {
+ // Synthesize mouse events to run this test.
+ sendMouseEvent(int_win, "target0", "mousemove");
+ sendMouseEvent(int_win, "target0", "mousedown");
+ sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
+ sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
+ sendMouseEvent(int_win, "target0", "mouseup");
+
+ window.addEventListener("message", function(aEvent) {
+ if (aEvent.data == "Test Touch") {
+ // Synthesize touch events to run this test.
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchmove");
+ sendTouchEvent(int_win, "target0", "touchend");
+ window.postMessage("Test Pen", "*");
+ } else if (aEvent.data == "Test Pen") {
+ // Synthesize pen events to run this test.
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
+ sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
+ sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
+ }
+ });
+ window.postMessage("Test Touch", "*");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_onpointercancel_touch-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_onpointercancel_touch-manual.html
new file mode 100644
index 0000000000..eb39b0bee3
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_onpointercancel_touch-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1000870</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchcancel");
+
+ // Need a touchend event to terminated the test gracefully.
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_pointerup_touch.html b/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_pointerup_touch.html
new file mode 100644
index 0000000000..67f1ead9a4
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_releasepointercapture_pointerup_touch.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1556703
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1556703</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_releasepointercapture_pointerup_touch.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchmove", {offsetY: 5});
+ sendTouchEvent(int_win, "target0", "touchmove", {offsetY: 10});
+ sendTouchEvent(int_win, "target0", "touchmove", {offsetY: 15});
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_sequence_at_implicit_release_on_drag-manual.html b/dom/events/test/pointerevents/test_wpt_pointerevent_sequence_at_implicit_release_on_drag-manual.html
new file mode 100644
index 0000000000..40a6be2e71
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_sequence_at_implicit_release_on_drag-manual.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>W3C pointerevent_sequence_at_implicit_release_on_drag-manual.html in Mochitest form</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target", "touchstart");
+ sendTouchEvent(int_win, "target", "touchmove");
+ sendTouchEvent(int_win, "target", "touchmove");
+ sendTouchEvent(int_win, "target", "touchcancel");
+ sendMouseEvent(int_win, "done", "mousedown");
+ sendMouseEvent(int_win, "done", "mouseup");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_pointerevent_setpointercapture_pointerup_touch.html b/dom/events/test/pointerevents/test_wpt_pointerevent_setpointercapture_pointerup_touch.html
new file mode 100644
index 0000000000..1287ae6107
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_pointerevent_setpointercapture_pointerup_touch.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1556703
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1556703</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="mochitest_support_external.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ function startTest() {
+ runTestInNewWindow("wpt/pointerevent_setpointercapture_pointerup_touch.html");
+ }
+ function executeTest(int_win) {
+ sendTouchEvent(int_win, "target0", "touchstart");
+ sendTouchEvent(int_win, "target0", "touchend");
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/test_wpt_touch_action.html b/dom/events/test/pointerevents/test_wpt_touch_action.html
new file mode 100644
index 0000000000..ee946f06b0
--- /dev/null
+++ b/dom/events/test/pointerevents/test_wpt_touch_action.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>W3C pointerevents/*touch-action*.html tests in Mochitest form</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="apz_test_utils.js"></script>
+ <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+var isWindows = (getPlatform() == "windows");
+
+var apz_touch_action_prefs = [
+ // Obviously we need touch-action support enabled for testing touch-action.
+ ["layout.css.touch_action.enabled", true],
+ // Dropping the touch slop to 0 makes the tests easier to write because
+ // we can just do a one-pixel drag to get over the pan threshold rather
+ // than having to hard-code some larger value.
+ ["apz.touch_start_tolerance", "0.0"],
+ // The touchstart from the drag can turn into a long-tap if the touch-move
+ // events get held up. Try to prevent that by making long-taps require
+ // a 10 second hold. Note that we also cannot enable chaos mode on this
+ // test for this reason, since chaos mode can cause the long-press timer
+ // to fire sooner than the pref dictates.
+ ["ui.click_hold_context_menus.delay", 10000],
+ // The subtests in this test do touch-drags to pan the page, but we don't
+ // want those pans to turn into fling animations, so we increase the
+ // fling-stop threshold velocity to absurdly high.
+ ["apz.fling_stopped_threshold", "10000"],
+ // The helper_div_pan's div gets a displayport on scroll, but if the
+ // test takes too long the displayport can expire before the new scroll
+ // position is synced back to the main thread. So we disable displayport
+ // expiry for these tests.
+ ["apz.displayport_expiry_ms", 0],
+ ["apz.test.fails_with_native_injection", isWindows],
+];
+
+function apzScriptInjector(name) {
+ return function(childWin) {
+ childWin._ACTIVE_TEST_NAME = name;
+ injectScript('/tests/SimpleTest/paint_listener.js', childWin)()
+ .then(injectScript('../apz_test_utils.js', childWin))
+ .then(injectScript('../apz_test_native_event_utils.js', childWin))
+ .then(injectScript('../touch_action_helpers.js', childWin));
+ };
+}
+
+// Each of these test names is turned into an entry in the |subtests| array
+// below.
+var testnames = [
+ 'pointerevent_touch-action-auto-css_touch-manual',
+ 'pointerevent_touch-action-button-test_touch-manual',
+ // this one runs as a web-platform-test since it's not a manual test
+ // 'pointerevent_touch-action-illegal',
+ 'pointerevent_touch-action-inherit_child-auto-child-none_touch-manual',
+ 'pointerevent_touch-action-inherit_child-none_touch-manual',
+ 'pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual',
+ 'pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual',
+ 'pointerevent_touch-action-inherit_highest-parent-none_touch-manual',
+ 'pointerevent_touch-action-inherit_parent-none_touch-manual',
+ // the keyboard-manual and mouse-manual tests require simulating keyboard/
+ // mouse input, rather than touch, so we're not going to do that here.
+ //'pointerevent_touch-action-keyboard-manual',
+ //'pointerevent_touch-action-mouse-manual',
+ 'pointerevent_touch-action-none-css_touch-manual',
+ 'pointerevent_touch-action-pan-x-css_touch-manual',
+ 'pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual',
+ 'pointerevent_touch-action-pan-x-pan-y_touch-manual',
+ 'pointerevent_touch-action-pan-y-css_touch-manual',
+ // disable this one because of intermittent failures. see bug 1292134.
+ // 'pointerevent_touch-action-span-test_touch-manual',
+ 'pointerevent_touch-action-svg-test_touch-manual',
+ 'pointerevent_touch-action-table-test_touch-manual',
+ // this one runs as a web-platform-test since it's not a manual test
+ //'pointerevent_touch-action-verification',
+];
+
+// Each entry in |subtests| is loaded in a new window. When loaded, it runs
+// the function returned by apzScriptInjector, which injects some helper JS
+// files into the vanilla unmodified W3C testcase, and simulates the necessary
+// user input to run the test.
+var subtests = [];
+for (var name of testnames) {
+ subtests.push({
+ 'file': 'wpt/' + name + '.html',
+ 'prefs': apz_touch_action_prefs,
+ 'onload': apzScriptInjector(name),
+ });
+}
+
+if (isApzEnabled()) {
+ SimpleTest.waitForExplicitFinish();
+ window.onload = function() {
+ runSubtestsSeriallyInFreshWindows(subtests)
+ .then(SimpleTest.finish, SimpleTest.finish);
+ };
+}
+
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/touch_action_helpers.js b/dom/events/test/pointerevents/touch_action_helpers.js
new file mode 100644
index 0000000000..2d6098112e
--- /dev/null
+++ b/dom/events/test/pointerevents/touch_action_helpers.js
@@ -0,0 +1,263 @@
+// Some common helpers
+
+function touchActionSetup(testDriver) {
+ add_completion_callback(subtestDone);
+ document.body.addEventListener("touchend", testDriver, { passive: true });
+}
+
+function touchActionSetupAndWaitTestDone(testDriver) {
+ let testDone = new Promise(resolve => {
+ add_completion_callback(resolve);
+ });
+
+ document.body.addEventListener("touchend", testDriver, { passive: true });
+ return testDone;
+}
+
+function touchScrollRight(aSelector = "#target0", aX = 20, aY = 20) {
+ var target = document.querySelector(aSelector);
+ return ok(
+ synthesizeNativeTouchDrag(target, aX + 40, aY, -40, 0),
+ "Synthesized horizontal drag"
+ );
+}
+
+function touchScrollDown(aSelector = "#target0", aX = 20, aY = 20) {
+ var target = document.querySelector(aSelector);
+ return ok(
+ synthesizeNativeTouchDrag(target, aX, aY + 40, 0, -40),
+ "Synthesized vertical drag"
+ );
+}
+
+function tapComplete() {
+ var button = document.getElementById("btnComplete");
+ return button.click();
+}
+
+function waitForResetScrollLeft(aSelector = "#target0") {
+ var target = document.querySelector(aSelector);
+ return new Promise(resolve => {
+ target.addEventListener("scroll", function onScroll() {
+ if (target.scrollLeft == 0) {
+ target.removeEventListener("scroll", onScroll);
+ resolve();
+ }
+ });
+ });
+}
+
+// The main body functions to simulate the input events required for the named test
+
+function* pointerevent_touch_action_auto_css_touch_manual(testDriver) {
+ let testDone = touchActionSetupAndWaitTestDone(testDriver);
+
+ yield touchScrollRight();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollDown();
+ yield testDone.then(testDriver);
+ subtestDone();
+}
+
+function* pointerevent_touch_action_button_test_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ yield touchScrollRight();
+ let resetScrollLeft = waitForResetScrollLeft();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ // Wait for resetting target0's scrollLeft to avoid the reset break the
+ // following scroll behaviors.
+ yield resetScrollLeft.then(testDriver);
+ yield touchScrollDown("#target0 > button");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0 > button");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_inherit_child_auto_child_none_touch_manual(
+ testDriver
+) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_inherit_child_none_touch_manual(
+ testDriver
+) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown("#target0 > div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0 > div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_inherit_child_pan_x_child_pan_x_touch_manual(
+ testDriver
+) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_inherit_child_pan_x_child_pan_y_touch_manual(
+ testDriver
+) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_inherit_highest_parent_none_touch_manual(
+ testDriver
+) {
+ let testDone = touchActionSetupAndWaitTestDone(testDriver);
+
+ yield touchScrollDown("#target0 > div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0 > div");
+ yield testDone.then(testDriver);
+ subtestDone();
+}
+
+function* pointerevent_touch_action_inherit_parent_none_touch_manual(
+ testDriver
+) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_none_css_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_pan_x_css_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_pan_x_pan_y_pan_y_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0 > div div");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_pan_x_pan_y_touch_manual(testDriver) {
+ let testDone = touchActionSetupAndWaitTestDone(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight();
+ yield testDone.then(testDriver);
+ subtestDone();
+}
+
+function* pointerevent_touch_action_pan_y_css_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_span_test_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ yield touchScrollRight();
+ let resetScrollLeft = waitForResetScrollLeft();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ // Wait for resetting target0's scrollLeft to avoid the reset break the
+ // following scroll behaviors.
+ yield resetScrollLeft.then(testDriver);
+ yield touchScrollDown("#testspan");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#testspan");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_svg_test_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ yield touchScrollRight();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ yield touchScrollDown("#target0", 250, 250);
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#target0", 250, 250);
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+function* pointerevent_touch_action_table_test_touch_manual(testDriver) {
+ touchActionSetup(testDriver);
+
+ yield touchScrollDown("#row1");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ yield touchScrollRight("#row1");
+ let resetScrollLeft = waitForResetScrollLeft();
+ yield waitForApzFlushedRepaints(testDriver);
+ yield setTimeout(testDriver, 2 * scrollReturnInterval);
+ // Wait for resetting target0's scrollLeft to avoid the reset break the
+ // following scroll behaviors.
+ yield resetScrollLeft.then(testDriver);
+ yield touchScrollDown("#cell3");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield touchScrollRight("#cell3");
+ yield waitForApzFlushedRepaints(testDriver);
+ yield tapComplete();
+}
+
+// This the stuff that runs the appropriate body function above
+
+var test = eval(_ACTIVE_TEST_NAME.replace(/-/g, "_"));
+waitUntilApzStable().then(runContinuation(test));
diff --git a/dom/events/test/pointerevents/wpt/compat/pointerevent_touch-action_two-finger_interaction-manual.html b/dom/events/test/pointerevents/wpt/compat/pointerevent_touch-action_two-finger_interaction-manual.html
new file mode 100644
index 0000000000..3537e0e1e9
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/compat/pointerevent_touch-action_two-finger_interaction-manual.html
@@ -0,0 +1,102 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Event: touch-action test for two-finger interaction</title>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+ <link rel="author" title="Google" href="http://www.google.com "/>
+ <link rel="help" href="https://compat.spec.whatwg.org/#touch-action" />
+ <meta name="assert" content="Tests that a two-finger pan gesture is cancelled in 'touch-action: pan-x pan-y' but is allowed in 'touch-action: pinch-zoom'"/>
+ <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script type="text/javascript" src="../pointerevent_support.js"></script>
+ <script type="text/javascript">
+ var event_log = [];
+ var active_pointers = 0;
+
+ function resetTestState() {
+ event_log = [];
+ active_pointers = 0;
+ }
+
+ function run() {
+ var test_pointer_events = [
+ setup_pointerevent_test("two-finger pan on 'touch-action: pan-x pan-y'", ["touch"]),
+ setup_pointerevent_test("two-finger pan on 'touch-action: pinch-zoom'", ["touch"])
+ ];
+ var expected_events = [
+ "pointerdown@black, pointerdown@black, pointerup@black, pointerup@black",
+ "pointerdown@grey, pointerdown@grey, pointercancel@grey, pointercancel@grey"
+ ];
+ var current_test_index = 0;
+
+ on_event(document.getElementById("done"), "click", function() {
+ test_pointer_events[current_test_index].step(function () {
+ assert_equals(active_pointers, 0);
+ assert_equals(event_log.join(", "), expected_events[current_test_index]);
+ });
+ event_log = [];
+
+ test_pointer_events[current_test_index++].done();
+ });
+
+ var targets = [document.getElementById("black"), document.getElementById("grey")];
+
+ ["pointerdown", "pointerup", "pointercancel"].forEach(function(eventName) {
+ targets.forEach(function(target){
+ on_event(target, eventName, function (event) {
+ event_log.push(event.type + "@" + event.target.id);
+
+ if (event.type == "pointerdown") {
+ active_pointers++;
+
+ } else {
+ active_pointers--;
+ }
+ });
+ });
+ });
+ }
+ </script>
+ <style>
+ .box {
+ width: 250px;
+ height: 150px;
+ float: left;
+ margin: 10px;
+ }
+
+ #black {
+ touch-action: pan-x pan-y;
+ background-color: black;
+ }
+
+ #grey {
+ touch-action: pinch-zoom;
+ background-color: grey;
+ }
+
+ #done {
+ float: left;
+ padding: 20px;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Event: touch-action test for two-finger interaction</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ Tests that a two-finger pan gesture is cancelled in 'touch-action: pan-x pan-y' but is allowed in 'touch-action: pinch-zoom'
+ </h4>
+ <ol>
+ <li>Touch on Black with two fingers and drag both fingers down at same speed.</li>
+ <li>Tap on Done.</li>
+ <li>Touch on Grey with two fingers and drag both fingers down at same speed.</li>
+ <li>Tap on Done.</li>
+ </ol>
+ <div class="box" id="black"></div>
+ <input type="button" id="done" value="Done" />
+ <div class="box" id="grey"></div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/html/pointerevent_drag_interaction-manual.html b/dom/events/test/pointerevents/wpt/html/pointerevent_drag_interaction-manual.html
new file mode 100644
index 0000000000..1a80d239b8
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/html/pointerevent_drag_interaction-manual.html
@@ -0,0 +1,103 @@
+<html>
+ <head>
+ <title>Pointer Events interaction with drag and drop</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="../pointerevent_support.js"></script>
+ <script>
+ var eventList = ['pointerdown', 'pointerup', 'pointercancel', 'gotpointercapture', 'lostpointercapture', 'dragstart', 'mousedown'];
+
+ PhaseEnum = {
+ DndWithoutCapture: 0,
+ DndWithCapture: 1,
+ DndWithCaptureMouse: 2,
+ DndPrevented: 3,
+ Done: 4,
+ };
+ var phase = PhaseEnum.DndWithoutCapture;
+ var received_events = [];
+ var pointerId = -1;
+
+ function resetTestState() {
+ phase = PhaseEnum.DndWithoutCapture;
+ }
+
+ function run() {
+ var test_pointerEvent = setup_pointerevent_test("pointer events vs drag and drop", ['mouse']);
+
+ var target0 = document.querySelector('#target0');
+ var target1 = document.querySelector('#target1');
+
+ function handleEvent(e) {
+ if (e.type == 'pointerdown') {
+ received_events = [];
+ if (phase == PhaseEnum.DndWithCapture) {
+ target0.setPointerCapture(e.pointerId);
+ } else if (phase == PhaseEnum.DndWithCaptureMouse) {
+ pointerId = e.pointerId;
+ }
+ }
+ if (e.type == 'mousedown') {
+ if (phase == PhaseEnum.DndWithCaptureMouse) {
+ target0.setPointerCapture(pointerId);
+ }
+ }
+ received_events.push(e.type + "@" + e.target.id);
+ if (e.type == 'dragstart') {
+ e.dataTransfer.setData('text/plain', 'dragstart test');
+ if (phase == PhaseEnum.DndPrevented)
+ e.preventDefault();
+ }
+ if (phase == PhaseEnum.DndWithoutCapture && e.type == 'pointercancel') {
+ phase++;
+ test(() => {
+ assert_equals(received_events.join(', '), "pointerdown@target0, mousedown@target0, dragstart@target0, pointercancel@target0", "Pointercancel should be fired with the expected order when drag operation starts.");
+ }, "Pointercancel when drag operation starts");
+ } else if (phase == PhaseEnum.DndWithCapture && e.type == 'lostpointercapture') {
+ test(() => {
+ assert_equals(received_events.join(', '), "pointerdown@target0, mousedown@target0, gotpointercapture@target0, dragstart@target0, pointercancel@target0, lostpointercapture@target0", "Pointercancel and lostpointercapture should be fired with the expected order when drag operation starts.");
+ }, "Pointercancel while capturing when drag operation starts");
+ phase++;
+ } else if (phase == PhaseEnum.DndWithCaptureMouse && e.type == 'lostpointercapture') {
+ test(() => {
+ assert_equals(received_events.join(', '), "pointerdown@target0, mousedown@target0, gotpointercapture@target0, dragstart@target0, pointercancel@target0, lostpointercapture@target0", "Pointercancel and lostpointercapture should be fired with the expected order when drag operation starts.");
+ }, "Pointercancel while capturing on mousedown when drag operation starts");
+ phase++;
+ } else if (phase == PhaseEnum.DndPrevented && e.type == 'pointerup') {
+ test(() => {
+ assert_equals(received_events.join(', '), "pointerdown@target0, mousedown@target0, dragstart@target0, pointerup@target1", "Pointerevent stream shouldn't get interrupted when drag is prevented.");
+ }, "Pointerevent stream when drag is prevented.");
+ phase++;
+ test_pointerEvent.done();
+ }
+ }
+ eventList.forEach(function(eventName) {
+ on_event(target0, eventName, handleEvent);
+ on_event(target1, eventName, handleEvent);
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events interaction with drag and drop</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ Test Description: This test checks that the pointercancel (and if needed lostpointercapture) is dispatched when drag starts.
+ <ol>
+ <li>Press down on the black square.</li>
+ <li>Move your pointer to purple square and release.</li>
+ <li>Repeat the first two steps.</li>
+ <li>Repeat the first two steps once again.</li>
+ <li>Repeat the first two steps once again.</li>
+ </ol>
+ Test passes if the proper behavior of the events is observed.
+ </h4>
+ <div id="testContainer">
+ <div draggable="true" id="target0"></div>
+ <div id="target1"></div>
+ </div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/idlharness.html b/dom/events/test/pointerevents/wpt/idlharness.html
new file mode 100644
index 0000000000..a4ba4c35f5
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/idlharness.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>idlharness test</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+
+<pre id='untested_idl' style='display:none'>
+[PrimaryGlobal]
+interface Window {
+};
+
+[TreatNonObjectAsNull]
+callback EventHandlerNonNull = any (Event event);
+typedef EventHandlerNonNull? EventHandler;
+
+[NoInterfaceObject]
+interface GlobalEventHandlers {
+};
+Window implements GlobalEventHandlers;
+
+interface Navigator {
+};
+
+interface Element {
+};
+
+interface HTMLElement : Element {
+};
+HTMLElement implements GlobalEventHandlers;
+
+interface Document {
+};
+Document implements GlobalEventHandlers;
+
+interface MouseEvent {
+};
+
+</pre>
+
+<pre id='idl'>
+dictionary PointerEventInit : MouseEventInit {
+ long pointerId = 0;
+ double width = 1;
+ double height = 1;
+ float pressure = 0;
+ float tangentialPressure = 0;
+ long tiltX = 0;
+ long tiltY = 0;
+ long twist = 0;
+ DOMString pointerType = "";
+ boolean isPrimary = false;
+};
+
+[Constructor(DOMString type, optional PointerEventInit eventInitDict)]
+interface PointerEvent : MouseEvent {
+ readonly attribute long pointerId;
+ readonly attribute double width;
+ readonly attribute double height;
+ readonly attribute float pressure;
+ readonly attribute float tangentialPressure;
+ readonly attribute long tiltX;
+ readonly attribute long tiltY;
+ readonly attribute long twist;
+ readonly attribute DOMString pointerType;
+ readonly attribute boolean isPrimary;
+};
+
+partial interface Element {
+ void setPointerCapture(long pointerId);
+ void releasePointerCapture(long pointerId);
+ boolean hasPointerCapture(long pointerId);
+};
+
+partial interface GlobalEventHandlers {
+ attribute EventHandler ongotpointercapture;
+ attribute EventHandler onlostpointercapture;
+ attribute EventHandler onpointerdown;
+ attribute EventHandler onpointermove;
+ attribute EventHandler onpointerup;
+ attribute EventHandler onpointercancel;
+ attribute EventHandler onpointerover;
+ attribute EventHandler onpointerout;
+ attribute EventHandler onpointerenter;
+ attribute EventHandler onpointerleave;
+};
+
+partial interface Navigator {
+ readonly attribute long maxTouchPoints;
+};
+</pre>
+<script>
+ var idl_array = new IdlArray();
+ idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
+ idl_array.add_idls(document.getElementById("idl").textContent);
+
+ // Note that I don't bother including Document here because there are still
+ // a bunch of differences between browsers around Document vs HTMLDocument.
+ idl_array.add_objects({
+ Window: ["window"],
+ Navigator: ["navigator"]});
+ idl_array.test();
+</script>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_attributes_hoverable_pointers-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_attributes_hoverable_pointers-manual.html
new file mode 100644
index 0000000000..0922ae7448
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_attributes_hoverable_pointers-manual.html
@@ -0,0 +1,143 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script>
+ var detected_pointertypes = {};
+ var detected_eventTypes = {};
+ var eventList = ['pointerover', 'pointerenter', 'pointermove', 'pointerdown', 'pointerup', 'pointerout', 'pointerleave'];
+ var expectedPointerId = NaN;
+
+ function resetTestState() {
+ detected_eventTypes = {};
+ document.getElementById("square1").style.visibility = 'visible';
+ document.getElementById('innerFrame').contentDocument.getElementById("square2").style.visibility = 'hidden';
+ expectedPointerId = NaN;
+ }
+ function checkPointerEventAttributes(event, targetBoundingClientRect, testNamePrefix) {
+ if (detected_eventTypes[event.type])
+ return;
+ var expectedEventType = eventList[Object.keys(detected_eventTypes).length];
+ detected_eventTypes[event.type] = true;
+ var pointerTestName = testNamePrefix + ' ' + expectedPointerType + ' ' + expectedEventType;
+
+ detected_pointertypes[event.pointerType] = true;
+
+ test(function() {
+ assert_equals(event.type, expectedEventType, "Event.type should be " + expectedEventType)
+ }, pointerTestName + "'s type should be " + expectedEventType);
+
+ // Test button and buttons
+ if (event.type == 'pointerdown') {
+ test(function() {
+ assert_true(event.button == 0, "Button attribute is 0")
+ }, pointerTestName + "'s button attribute is 0 when left mouse button is pressed.");
+ test(function() {
+ assert_true(event.buttons == 1, "Buttons attribute is 1")
+ }, pointerTestName + "'s buttons attribute is 1 when left mouse button is pressed.");
+ } else if (event.type == 'pointerup') {
+ test(function() {
+ assert_true(event.button == 0, "Button attribute is 0")
+ }, pointerTestName + "'s button attribute is 0 when left mouse button is just released.");
+ test(function() {
+ assert_true(event.buttons == 0, "Buttons attribute is 0")
+ }, pointerTestName + "'s buttons attribute is 0 when left mouse button is just released.");
+ } else {
+ test(function() {
+ assert_true(event.button == -1, "Button attribute is -1")
+ }, pointerTestName + "'s button is -1 when mouse buttons are in released state.");
+ test(function() {
+ assert_true(event.buttons == 0, "Buttons attribute is 0")
+ }, pointerTestName + "'s buttons is 0 when mouse buttons are in released state.");
+ }
+
+ // Test clientX and clientY
+ if (event.type != 'pointerout' && event.type != 'pointerleave' ) {
+ test(function () {
+ assert_true(event.clientX >= targetBoundingClientRect.left && event.clientX < targetBoundingClientRect.right && event.clientY >= targetBoundingClientRect.top && event.clientY < targetBoundingClientRect.bottom, "ClientX/Y should be in the boundaries of the box");
+ }, pointerTestName + "'s ClientX and ClientY attributes are correct.");
+ } else {
+ test(function () {
+ assert_true(event.clientX < targetBoundingClientRect.left || event.clientX > targetBoundingClientRect.right - 1 || event.clientY < targetBoundingClientRect.top || event.clientY > targetBoundingClientRect.bottom - 1, "ClientX/Y should be out of the boundaries of the box");
+ }, pointerTestName + "'s ClientX and ClientY attributes are correct.");
+ }
+
+ check_PointerEvent(event, testNamePrefix);
+
+ // Test isPrimary value
+ test(function () {
+ assert_equals(event.isPrimary, true, "isPrimary should be true");
+ }, pointerTestName + ".isPrimary attribute is correct.");
+
+ // Test pointerId value
+ if (isNaN(expectedPointerId)) {
+ expectedPointerId = event.pointerId;
+ } else {
+ test(function () {
+ assert_equals(event.pointerId, expectedPointerId, "pointerId should remain the same for the same active pointer");
+ }, pointerTestName + ".pointerId should be the same as previous pointer events for this active pointer.");
+ }
+ }
+
+ function run() {
+ var test_pointerEvent = setup_pointerevent_test("pointerevent attributes", HOVERABLE_POINTERS);
+ var square1 = document.getElementById("square1");
+ var rectSquare1 = square1.getBoundingClientRect();
+ var innerFrame = document.getElementById('innerFrame');
+ var square2 = innerFrame.contentDocument.getElementById('square2');
+ var rectSquare2 = square2.getBoundingClientRect();
+
+ eventList.forEach(function(eventName) {
+ on_event(square1, eventName, function (event) {
+ if (square1.style.visibility == 'hidden')
+ return;
+ checkPointerEventAttributes(event, rectSquare1, "");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square1.style.visibility = 'hidden';
+ detected_eventTypes = {};
+ square2.style.visibility = 'visible';
+ expectedPointerId = NaN;
+ }
+ });
+ on_event(square2, eventName, function (event) {
+ checkPointerEventAttributes(event, rectSquare2, "Inner frame ");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square2.style.visibility = 'hidden';
+ test_pointerEvent.done();
+ }
+ });
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events hoverable pointer attributes test</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ Test Description: This test checks the properties of hoverable pointer events. If you are using hoverable pen don't leave the range of digitizer while doing the instructions.
+ <ol>
+ <li>Move your pointer over the black square and click on it.</li>
+ <li>Then move it off the black square so that it disappears.</li>
+ <li>When red square appears move your pointer over the red square and click on it.</li>
+ <li>Then move it off the red square.</li>
+ </ol>
+
+ Test passes if the proper behavior of the events is observed.
+ </h4>
+ <div id="square1" class="square"></div>
+ <iframe id="innerFrame" src="resources/pointerevent_attributes_hoverable_pointers-iframe.html"></iframe>
+ <div class="spacer"></div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
+
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_attributes_nohover_pointers-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_attributes_nohover_pointers-manual.html
new file mode 100644
index 0000000000..0fd7904ef0
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_attributes_nohover_pointers-manual.html
@@ -0,0 +1,126 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script>
+ var detected_pointertypes = {};
+ var detected_eventTypes = {};
+ var eventList = ['pointerover', 'pointerenter', 'pointerdown', 'pointerup', 'pointerout', 'pointerleave'];
+ var expectedPointerId = NaN;
+
+ function resetTestState() {
+ detected_eventTypes = {};
+ document.getElementById("square1").style.visibility = 'visible';
+ document.getElementById('innerFrame').contentDocument.getElementById("square2").style.visibility = 'hidden';
+ }
+ function checkPointerEventAttributes(event, targetBoundingClientRect, testNamePrefix) {
+ if (detected_eventTypes[event.type])
+ return;
+ var expectedEventType = eventList[Object.keys(detected_eventTypes).length];
+ detected_eventTypes[event.type] = true;
+ var pointerTestName = testNamePrefix + ' ' + expectedPointerType + ' ' + expectedEventType;
+
+ detected_pointertypes[event.pointerType] = true;
+
+ test(function() {
+ assert_equals(event.type, expectedEventType, "Event.type should be " + expectedEventType)
+ }, pointerTestName + "'s type should be " + expectedEventType);
+
+ // Test button and buttons
+ test(function() {
+ assert_true(event.button == 0, "Button attribute is 0")
+ }, pointerTestName + "'s button attribute is 0 when left mouse button is pressed.");
+
+ if (event.type == 'pointerdown' || event.type == 'pointerover' || event.type == 'pointerenter') {
+ test(function() {
+ assert_true(event.buttons == 1, "Buttons attribute is 1")
+ }, pointerTestName + "'s buttons attribute is 1 when left mouse button is pressed.");
+ } else {
+ test(function() {
+ assert_true(event.buttons == 0, "Buttons attribute is 0")
+ }, pointerTestName + "'s buttons is 0 when mouse buttons are in released state.");
+ }
+
+ // Test clientX and clientY
+ test(function () {
+ assert_true(event.clientX >= targetBoundingClientRect.left && event.clientX < targetBoundingClientRect.right && event.clientY >= targetBoundingClientRect.top && event.clientY < targetBoundingClientRect.bottom, "ClientX/Y should be in the boundaries of the box");
+ }, pointerTestName + "'s ClientX and ClientY attributes are correct.");
+
+ check_PointerEvent(event, testNamePrefix);
+
+ // Test isPrimary
+ test(function () {
+ assert_equals(event.isPrimary, true, "isPrimary should be true");
+ }, pointerTestName + ".isPrimary attribute is correct.");
+
+ // Test pointerId value
+ if (isNaN(expectedPointerId)) {
+ expectedPointerId = event.pointerId;
+ } else {
+ test(function () {
+ assert_equals(event.pointerId, expectedPointerId, "pointerId should remain the same for the same active pointer");
+ }, pointerTestName + ".pointerId should be the same as previous pointer events for this active pointer.");
+ }
+ }
+
+ function run() {
+ var test_pointerEvent = setup_pointerevent_test("pointerevent attributes", NOHOVER_POINTERS);
+ var square1 = document.getElementById("square1");
+ var rectSquare1 = square1.getBoundingClientRect();
+ var innerFrame = document.getElementById('innerFrame');
+ var square2 = innerFrame.contentDocument.getElementById('square2');
+ var rectSquare2 = square2.getBoundingClientRect();
+
+ eventList.forEach(function(eventName) {
+ on_event(square1, eventName, function (event) {
+ if (square1.style.visibility == 'hidden')
+ return;
+ checkPointerEventAttributes(event, rectSquare1, "");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square1.style.visibility = 'hidden';
+ detected_eventTypes = {};
+ square2.style.visibility = 'visible';
+ expectedPointerId = NaN;
+ }
+ });
+ on_event(square2, eventName, function (event) {
+ checkPointerEventAttributes(event, rectSquare2, "Inner frame ");
+ if (Object.keys(detected_eventTypes).length == eventList.length) {
+ square2.style.visibility = 'hidden';
+ test_pointerEvent.done();
+ }
+ });
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events no-hover pointer attributes test</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ Test Description: This test checks the properties of pointer events that do not support hover.
+ <ol>
+ <li>Tap the black square.</li>
+ <li>Then move it off the black square so that it disappears.</li>
+ <li>When the red square appears tap on that as well.</li>
+ </ol>
+
+ Test passes if the proper behavior of the events is observed.
+ </h4>
+ <div id="square1" class="square"></div>
+ <iframe id="innerFrame" src="resources/pointerevent_attributes_hoverable_pointers-iframe.html"></iframe>
+ <div class="spacer"></div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
+
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_boundary_events_in_capturing-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_boundary_events_in_capturing-manual.html
new file mode 100644
index 0000000000..0de4d55ed1
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_boundary_events_in_capturing-manual.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events boundary events in capturing tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script>
+ var detected_pointertypes = {};
+ var eventList = All_Pointer_Events;
+ PhaseEnum = {
+ WaitingForDown: "down",
+ WaitingForFirstMove: "firstMove",
+ WaitingForSecondMove: "secondMove",
+ WaitingForUp: "up"
+ }
+ var phase = PhaseEnum.WaitingForDown;
+ var eventsRecieved = [];
+
+ function resetTestState() {
+ eventsRecieved = [];
+ phase = PhaseEnum.WaitingForDown;
+ }
+ function run() {
+ var test_pointerEvent = setup_pointerevent_test("pointerevent boundary events in capturing", ALL_POINTERS);
+ var target = document.getElementById("target0");
+ var listener = document.getElementById("listener");
+
+ eventList.forEach(function(eventName) {
+ on_event(target, eventName, function (event) {
+ if (phase == PhaseEnum.WaitingForDown) {
+ if (eventName == 'pointerdown') {
+ listener.setPointerCapture(event.pointerId);
+ phase = PhaseEnum.WaitingForFirstMove;
+ }
+ } else if (phase == PhaseEnum.WaitingForUp) {
+ if (event.type == 'pointerup')
+ test_pointerEvent.done();
+ } else {
+ eventsRecieved.push(event.type + '@target');
+ if (phase == PhaseEnum.WaitingForSecondMove && event.type == 'pointermove') {
+ test(function () {
+ checkPointerEventType(event);
+ assert_array_equals(eventsRecieved, ['lostpointercapture@listener', 'pointerout@listener', 'pointerleave@listener', 'pointerover@target', 'pointerenter@target', 'pointermove@target'],
+ 'lostpointercapture and pointerout/leave should be dispatched to the capturing target and pointerover/enter should be dispatched to the hit-test element before the first pointermove event after releasing pointer capture');
+ }, expectedPointerType + " pointer events boundary events when releasing capture");
+ phase = PhaseEnum.WaitingForUp;
+ }
+ }
+ });
+ on_event(listener, eventName, function (event) {
+ if (phase == PhaseEnum.WaitingForDown)
+ return;
+ eventsRecieved.push(event.type + '@listener');
+ if (phase == PhaseEnum.WaitingForFirstMove && eventName == 'pointermove') {
+ test(function () {
+ checkPointerEventType(event);
+ assert_array_equals(eventsRecieved, ['pointerout@target', 'pointerleave@target', 'pointerover@listener', 'pointerenter@listener', 'gotpointercapture@listener', 'pointermove@listener'],
+ 'pointerout/leave should be dispatched to the previous target and pointerover/enter and gotpointercapture should be dispatched to the capturing element before the first captured pointermove event');
+ }, expectedPointerType + " pointer events boundary events when receiving capture");
+ listener.releasePointerCapture(event.pointerId);
+ eventsRecieved = [];
+ phase = PhaseEnum.WaitingForSecondMove;
+ }
+ });
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events boundary events in capturing</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ Test Description: This test checks the boundary events of pointer events while the capturing changes. If you are using hoverable pen don't leave the range of digitizer while doing the instructions.
+ <ol>
+ <li>Move your pointer over the black square</li>
+ <li>Press down the pointer (i.e. press left button with mouse or touch the screen with finger or pen).</li>
+ <li>Drag the pointer within the black square.</li>
+ <li>Release the pointer.</li>
+ </ol>
+
+ Test passes if the proper behavior of the events is observed.
+ </h4>
+ <div id="target0" class="touchActionNone">
+ </div>
+ <div id="listener">Do not hover over or touch this element. </div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
+
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_change-touch-action-onpointerdown_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_change-touch-action-onpointerdown_touch-manual.html
new file mode 100644
index 0000000000..04d56cb7a5
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_change-touch-action-onpointerdown_touch-manual.html
@@ -0,0 +1,135 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Change touch-action on pointerdown</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ background: black;
+ width: 700px;
+ height: 430px;
+ color: white;
+ overflow-y: auto;
+ overflow-x: auto;
+ white-space: nowrap;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4>Test Description: Press and hold your touch. Try to scroll text in any direction.
+ Then release your touch and try to scroll again. Expected: no panning.
+ </h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0" style="touch-action: auto;">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ var styleIsChanged = false;
+ var scrollIsReceived = false;
+ var firstTouchCompleted = false;
+ var countToPass = 50;
+ var xScr0, yScr0, xScr1, yScr1;
+
+ setup({ explicit_done: true });
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ on_event(target0, 'scroll', function(event) {
+ if(!scrollIsReceived && firstTouchCompleted) {
+ test(function() {
+ failOnScroll();
+ }, "scroll was received while shouldn't");
+ scrollIsReceived = true;
+ }
+ done();
+ });
+
+ on_event(target0, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ if(!styleIsChanged) {
+ var before = document.getElementById('target0').style.touchAction;
+
+ document.getElementById('target0').style.touchAction = 'none';
+
+ var after = document.getElementById('target0').style.touchAction;
+
+ test(function() {
+ assert_true(before != after, "touch-action was changed");
+ }, "touch-action was changed");
+
+ styleIsChanged = true;
+ }
+ });
+
+ on_event(target0, 'pointerup', function(event) {
+ firstTouchCompleted = true;
+ });
+ }
+ </script>
+ <h1>touch-action: auto to none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_constructor.html b/dom/events/test/pointerevents/wpt/pointerevent_constructor.html
new file mode 100644
index 0000000000..b2a779d1f7
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_constructor.html
@@ -0,0 +1,106 @@
+<!doctype html>
+<html>
+ <head>
+ <title>PointerEvent: Constructor test</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ </head>
+ <body>
+ <h1>PointerEvent: Dispatch custom event</h1>
+ <h4>Test Description: This test checks if PointerEvent constructor works properly using synthetic pointerover and pointerout events. For valid results, this test must be run without generating real (trusted) pointerover or pointerout events on the black rectangle below.</h4>
+ <div id="target0"></div>
+ <script>
+ var detected_pointertypes = {};
+ add_completion_callback(showPointerTypes);
+
+ async_test(function() {
+ var target0 = document.getElementById("target0");
+ // set values for non-default constructor
+ var testBubbles = true;
+ var testCancelable = true;
+ var testPointerId = 42;
+ var testPointerType = 'pen';
+ var testClientX = 300;
+ var testClientY = 500;
+ var testWidth = 3;
+ var testHeight = 5;
+ var testTiltX = -45;
+ var testTiltY = 30;
+ var testButton = 0;
+ var testButtons = 1;
+ var testPressure = 0.4;
+ var testIsPrimary = true;
+
+ on_event(target0, "pointerover", this.step_func(function(event) {
+ detected_pointertypes[ event.pointerType ] = true;
+ generate_tests(assert_equals, [
+ ["custom bubbles", event.bubbles, testBubbles],
+ ["custom cancelable", event.cancelable, testCancelable],
+ ["custom pointerId", event.pointerId, testPointerId],
+ ["custom pointerType", event.pointerType, testPointerType],
+ ["custom button", event.button, testButton],
+ ["custom buttons", event.buttons, testButtons],
+ ["custom width", event.width, testWidth],
+ ["custom height", event.height, testHeight],
+ ["custom clientX", event.clientX, testClientX],
+ ["custom clientY", event.clientY, testClientY],
+ ["custom tiltX", event.tiltX, testTiltX],
+ ["custom tiltY", event.tiltY, testTiltY],
+ ["custom isPrimary", event.isPrimary, testIsPrimary]
+ ]);
+ test(function() {
+ assert_approx_equals(event.pressure, testPressure, 0.00000001, "custom pressure: ");
+ }, "custom pressure: ");
+ }));
+
+ on_event(target0, "pointerout", this.step_func(function(event) {
+ generate_tests(assert_equals, [
+ ["default pointerId", event.pointerId, 0],
+ ["default pointerType", event.pointerType, ""],
+ ["default width", event.width, 1],
+ ["default height", event.height, 1],
+ ["default tiltX", event.tiltX, 0],
+ ["default tiltY", event.tiltY, 0],
+ ["default pressure", event.pressure, 0],
+ ["default isPrimary", event.isPrimary, false]
+ ]);
+ }));
+
+ on_event(window, "load", this.step_func_done(function() {
+ assert_not_equals(window.PointerEvent, undefined);
+
+ var pointerEventCustom = new PointerEvent("pointerover",
+ {bubbles: testBubbles,
+ cancelable: testCancelable,
+ pointerId: testPointerId,
+ pointerType: testPointerType,
+ width: testWidth,
+ height: testHeight,
+ clientX: testClientX,
+ clientY: testClientY,
+ tiltX: testTiltX,
+ tiltY: testTiltY,
+ button: testButton,
+ buttons: testButtons,
+ pressure: testPressure,
+ isPrimary: testIsPrimary
+ });
+ // A PointerEvent created with a PointerEvent constructor must have all its attributes set to the corresponding values provided to the constructor.
+ // For attributes where values are not provided to the constructor, the corresponding default values must be used.
+ // TA: 12.1
+ target0.dispatchEvent(pointerEventCustom);
+ var pointerEventDefault = new PointerEvent("pointerout");
+ target0.dispatchEvent(pointerEventDefault);
+ }, "PointerEvent constructor"));
+ })
+ </script>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_multiple_primary_pointers_boundary_events-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_multiple_primary_pointers_boundary_events-manual.html
new file mode 100644
index 0000000000..eb758c7073
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_multiple_primary_pointers_boundary_events-manual.html
@@ -0,0 +1,145 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Event: Boundary compatibility events for multiple primary pointers</title>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+ <link rel="author" title="Google" href="http://www.google.com "/>
+ <meta name="assert" content="When more than one primary pointers are active, each will have an independent sequence of pointer boundary events but the compatibilty mouse boundary events have their own sequence."/>
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script type="text/javascript">
+ var test_pointerEvent = async_test("Multi-pointer boundary compat events");
+ add_completion_callback(end_of_test);
+
+ var detected_pointertypes = {};
+ var event_log = [];
+
+ // These two ids help us detect two different pointing devices.
+ var first_entry_pointer_id = -1;
+ var second_entry_pointer_id = -1;
+
+ // Current node for each pointer id
+ var current_node_for_id = {};
+
+ function end_of_test() {
+ showLoggedEvents();
+ showPointerTypes();
+ }
+
+ function end_of_interaction() {
+ test(function () {
+ assert_equals(event_log.join(", "),
+ "mouseover@target0, mouseenter@target0, mouseout@target0, mouseleave@target0, " +
+ "mouseover@target1, mouseenter@target1, mouseout@target1, mouseleave@target1, " +
+ "mouseover@target0, mouseenter@target0, mouseout@target0, mouseleave@target0"
+ );
+ }, "Event log");
+
+ test_pointerEvent.done(); // complete test
+ }
+
+ function log_event(label) {
+ event_log.push(label);
+ }
+
+ function run() {
+ on_event(document.getElementById("done"), "click", end_of_interaction);
+
+ var target_list = ["target0", "target1"];
+ var pointer_event_list = ["pointerenter", "pointerleave", "pointerover", "pointerout", "pointerdown"];
+ var mouse_event_list = ["mouseenter", "mouseleave", "mouseover", "mouseout"];
+
+ target_list.forEach(function(targetId) {
+ var target = document.getElementById(targetId);
+
+ pointer_event_list.forEach(function(eventName) {
+ on_event(target, eventName, function (event) {
+ var label = event.type + "@" + targetId;
+
+ detected_pointertypes[event.pointerType] = true;
+
+ if (!event.isPrimary) {
+ test(function () {
+ assert_unreached("Non-primary pointer " + label);
+ }, "Non-primary pointer " + label);
+ }
+
+ if (event.type === "pointerenter") {
+ var pointer_id = event.pointerId;
+ if (current_node_for_id[pointer_id] !== undefined) {
+ test(function () {
+ assert_unreached("Double entry " + label);
+ }, "Double entry " + label);
+ }
+ current_node_for_id[pointer_id] = event.target;
+
+ // Test that two different pointing devices are used
+ if (first_entry_pointer_id === -1) {
+ first_entry_pointer_id = pointer_id;
+ } else if (second_entry_pointer_id === -1) {
+ second_entry_pointer_id = pointer_id;
+ test(function () {
+ assert_true(first_entry_pointer_id !== second_entry_pointer_id);
+ }, "Different pointing devices");
+ }
+ } else if (event.type === "pointerleave") {
+ var pointer_id = event.pointerId;
+ if (current_node_for_id[pointer_id] !== event.target) {
+ test(function () {
+ assert_unreached("Double exit " + label);
+ }, "Double exit " + label);
+ }
+ current_node_for_id[pointer_id] = undefined;
+ }
+ });
+ });
+
+ mouse_event_list.forEach(function(eventName) {
+ on_event(target, eventName, function (event) {
+ log_event(event.type + "@" + targetId);
+ });
+ });
+ });
+ }
+ </script>
+ <style>
+ #target0, #target1 {
+ margin: 20px;
+ }
+
+ #done {
+ margin: 20px;
+ border: 2px solid black;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Event: Boundary compatibility events for multiple primary pointers</h1>
+ <h4>
+ When more than one primary pointers are active, each will have an independent sequence of pointer boundary events but the compatibilty mouse boundary events have their own sequence.
+ </h4>
+ Instruction:
+ <ol>
+ <li>Move the mouse directly into Target0 (without going through Target1), and then leave the mouse there unmoved.</li>
+ <li>Tap directly on Target1 with a finger or a stylus, and then lift the finger/stylus off the screen/digitizer without crossing Target1 boundary.</li>
+ <li>Move the mouse into Target0 (if not there already) and move inside it.</li>
+ <li>Click Done (without passing over Target1).</li>
+ </ol>
+ <div id="done">
+ Done
+ </div>
+ <div id="target0">
+ Target0
+ </div>
+ <div id="target1">
+ Target1
+ </div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>The following events were logged: <span id="event-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_pointerId_scope-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_pointerId_scope-manual.html
new file mode 100644
index 0000000000..3640cb6f6b
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_pointerId_scope-manual.html
@@ -0,0 +1,82 @@
+<!doctype html>
+<html>
+ <!--
+Test cases for Pointer Events v1 spec
+This document references Test Assertions (abbrev TA below) written by Cathy Chan
+http://www.w3.org/wiki/PointerEvents/TestAssertions
+-->
+ <head>
+ <title>Pointer Events pointerdown tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script>
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("pointerId of an active pointer is the same across iframes");
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+ var detected_pointertypes = {};
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var pointerover_pointerId = null;
+ var pointerover_pointerType = null;
+
+ var eventList = ['pointerenter', 'pointerover', 'pointermove', 'pointerout', 'pointerleave'];
+ var receivedEvents = {};
+ var receivedEventsInnerFrame = {};
+
+
+ function checkPointerId(event, inner) {
+ detected_pointertypes[event.pointerType] = true;
+ var eventName = (inner ? "inner frame " : "" ) + event.type;
+ test_pointerEvent.step(function() {
+ assert_equals(event.pointerId, pointerover_pointerId, "PointerId of " + eventName + " is not correct");
+ assert_equals(event.pointerType, pointerover_pointerType, "PointerType of " + eventName + " is not correct");
+ }, eventName + ".pointerId were the same as first pointerover");
+ }
+
+ on_event(window, "message", function(event) {
+ var pe_event = JSON.parse(event.data);
+ receivedEventsInnerFrame[pe_event.type] = 1;
+ checkPointerId(pe_event, true);
+ if (Object.keys(receivedEvents).length == eventList.length && Object.keys(receivedEventsInnerFrame).length == eventList.length)
+ test_pointerEvent.done();
+ });
+
+ eventList.forEach(function(eventName) {
+ on_event(target0, eventName, function (event) {
+ if (pointerover_pointerId === null && event.type == 'pointerover') {
+ pointerover_pointerId = event.pointerId;
+ pointerover_pointerType = event.pointerType;
+ } else {
+ checkPointerId(event, false);
+ }
+ receivedEvents[event.type] = 1;
+ });
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events pointerdown tests</h1>
+ Complete the following actions:
+ <ol>
+ <li>Start with your pointing device outside of black box, then move it into black box. If using touch just press in black box and don't release.
+ <li>Move your pointing device into purple box (without leaving the digitizer range if you are using hover supported pen or without releasing touch if using touch). Then move it out of the purple box.
+ </ol>
+ <div id="target0" class="touchActionNone">
+ </div>
+ <iframe src="resources/pointerevent_pointerId_scope-iframe.html" id="innerframe"></iframe>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_pointercancel_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_pointercancel_touch-manual.html
new file mode 100644
index 0000000000..70a65eeb5c
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_pointercancel_touch-manual.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<html>
+ <head>
+ <title>PointerCancel - touch</title>
+ <meta name="viewport" content="width=device-width">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ </head>
+ <body class="scrollable" onload="run()">
+ <h1>pointercancel test</h1>
+ <h3>Warning: this test works properly only for devices that have touchscreen</h3>
+ <h4>
+ Test Description: This test checks if pointercancel event triggers.
+ <p>Start touch over the black rectangle and then move your finger to scroll the page.</p>
+ </h4>
+ <p>
+ <div id="target0" style="background: black"></div>
+ <script>
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("pointercancel event received");
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+
+ var pointerdown_event = null;
+ var pointercancel_event = null;
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ on_event(target0, "pointerdown", function (event) {
+ pointerdown_event = event;
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ on_event(target0, "pointercancel", function (event) {
+ pointercancel_event = event;
+ test_pointerEvent.step(function () {
+ assert_not_equals(pointerdown_event, null, "pointerdown was received: ");
+ assert_equals(event.pointerId, pointerdown_event.pointerId, "pointerId should be the same for pointerdown and pointercancel");
+ assert_equals(event.pointerType, pointerdown_event.pointerType, "pointerType should be the same for pointerdown and pointercancel");
+ assert_equals(event.isPrimary, pointerdown_event.isPrimary, "isPrimary should be the same for pointerdown and pointercancel");
+ check_PointerEvent(event);
+ });
+ });
+
+ on_event(target0, "pointerout", function (event) {
+ test_pointerEvent.step(function () {
+ assert_not_equals(pointercancel_event, null, "pointercancel was received before pointerout: ");
+ assert_equals(event.pointerId, pointerdown_event.pointerId, "pointerId should be the same for pointerout and pointercancel");
+ assert_equals(event.pointerType, pointerdown_event.pointerType, "pointerType should be the same for pointerout and pointercancel");
+ assert_equals(event.isPrimary, pointerdown_event.isPrimary, "isPrimary should be the same for pointerout and pointercancel");
+ });
+ });
+
+ on_event(target0, "pointerleave", function (event) {
+ test_pointerEvent.step(function () {
+ assert_not_equals(pointercancel_event, null, "pointercancel was received before pointerleave: ");
+ assert_equals(event.pointerId, pointerdown_event.pointerId, "pointerId should be the same for pointerleave and pointercancel");
+ assert_equals(event.pointerType, pointerdown_event.pointerType, "pointerType should be the same for pointerleave and pointercancel");
+ assert_equals(event.isPrimary, pointerdown_event.isPrimary, "isPrimary should be the same for pointerleave and pointercancel");
+ });
+ test_pointerEvent.done();
+ });
+ }
+ </script>
+ <h1>Pointer Events pointercancel Tests</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_pointerleave_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_pointerleave_after_pointercancel_touch-manual.html
new file mode 100644
index 0000000000..56be26549f
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_pointerleave_after_pointercancel_touch-manual.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<html>
+ <head>
+ <title>pointerleave after pointercancel</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ </head>
+ <body class="scrollable" onload="run()">
+ <h2>pointerleave after pointercancel</h2>
+ <h4>Test Description: This test checks if pointerleave event triggers after pointercancel. Start touch on the black rectangle and move your touch to scroll in any direction. </h4>
+ <p>Note: this test is for touch devices only</p>
+ <div id="target0"></div>
+ <script>
+ var test_pointerleave = async_test("pointerleave event received");
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+
+ var eventTested = false;
+ var pointercancel_event = null;
+ var detected_pointertypes = {};
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ on_event(target0, "pointercancel", function (event) {
+ detected_pointertypes[event.pointerType] = true;
+ pointercancel_event = event;
+ });
+
+ // After firing the pointercancel event the pointerleave event must be dispatched.
+ // TA: 4.3.1
+ on_event(target0, "pointerleave", function (event) {
+ if(event.pointerType == 'touch') {
+ if(pointercancel_event != null) {
+ if(eventTested == false) {
+ test_pointerleave.step(function() {
+ assert_equals(event.pointerType, pointercancel_event.pointerType, "pointerType is same for pointercancel and pointerleave");
+ assert_equals(event.isPrimary, pointercancel_event.isPrimary, "isPrimary is same for pointercancel and pointerleave");
+ });
+ eventTested = true;
+ test_pointerleave.done();
+ }
+ }
+ else {
+ test_pointerleave.step(function() {
+ assert_unreached("pointerleave received before pointercancel");
+ }, "pointerleave received before pointercancel");
+ }
+ }
+ });
+ }
+
+ </script>
+ <h1>Pointer Events pointerleave tests</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_pointerleave_pen-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_pointerleave_pen-manual.html
new file mode 100644
index 0000000000..38a2f69792
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_pointerleave_pen-manual.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Event: Dispatch pointerleave (pen). </title>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+ <link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
+ <meta name="assert" content="When a pointing device that supports hover (pen stylus) leaves the range of the digitizer while over an element, the pointerleave event must be dispatched."/>
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <!-- /resources/testharness.js -->
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script type="text/javascript">
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("pointerleave event"); // set up test harness
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ on_event(target0, "pointerleave", function (event) {
+ detected_pointertypes[event.pointerType] = true;
+ check_PointerEvent(event);
+ test_pointerEvent.step(function () {
+ assert_equals(event.pointerType, "pen", "Test should be run using a pen as input");
+ assert_equals(event.type, "pointerleave", "The " + event.type + " event was received");
+ assert_true((event.clientX > target0.getBoundingClientRect().left)&&
+ (event.clientX < target0.getBoundingClientRect().right)&&
+ (event.clientY > target0.getBoundingClientRect().top)&&
+ (event.clientY < target0.getBoundingClientRect().bottom),
+ "pointerleave should be received inside of target bounds");
+ });
+ test_pointerEvent.done(); // complete test
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Event: Dispatch pointerleave (pen)</h1>
+ <h4>
+ Test Description:
+ When a pointing device that supports hover (pen stylus) leaves the range of the digitizer while over an element, the pointerleave event must be dispatched.
+ </h4>
+ <br />
+ <div id="target0">
+ Use a pen to hover over then lift up away from this element.
+ </div>
+ <div id="complete-notice">
+ <p>Test complete: Scroll to Summary to view Pass/Fail Results.</p>
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_pointerout_after_pointercancel_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_pointerout_after_pointercancel_touch-manual.html
new file mode 100644
index 0000000000..1888591a7c
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_pointerout_after_pointercancel_touch-manual.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<html>
+ <head>
+ <title>pointerout</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ </head>
+ <body class="scrollable" onload="run()">
+ <h2>pointerout</h2>
+ <h4>Test Description: This test checks if pointerout event triggers after pointercancel. Start touch on the black rectangle and move your touch to scroll in any direction. </h4>
+ <p>Note: this test is for touch devices only</p>
+ <div id="target0"></div>
+ <script>
+ var test_pointerout = async_test("pointerout event received");
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+
+ var eventTested = false;
+ var pointercancel_event = null;
+ var detected_pointertypes = {};
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ on_event(target0, "pointercancel", function (event) {
+ detected_pointertypes[event.pointerType] = true;
+ pointercancel_event = event;
+ });
+
+ // After firing the pointercancel event the pointerout event must be dispatched.
+ // TA: 4.3
+ on_event(target0, "pointerout", function (event) {
+ if(event.pointerType == 'touch') {
+ if(pointercancel_event != null) {
+ if (eventTested == false) {
+ test_pointerout.step(function() {
+ assert_equals(event.pointerType, pointercancel_event.pointerType, "pointerType is same for pointercancel and pointerout");
+ assert_equals(event.isPrimary, pointercancel_event.isPrimary, "isPrimary is same for pointercancel and pointerout");
+ });
+ eventTested = true;
+ test_pointerout.done();
+ }
+ }
+ else {
+ test_pointerout.step(function() {
+ assert_true(false,
+ "pointercancel received before pointerout");
+ }, "pointercancel received before pointerout");
+ }
+ }
+ });
+ }
+
+ </script>
+ <h1>Pointer Events pointerout tests</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_pointerout_pen-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_pointerout_pen-manual.html
new file mode 100644
index 0000000000..3973948c16
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_pointerout_pen-manual.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<html>
+ <head>
+ <title>pointerout</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ </head>
+ <body onload="run()">
+ <h2>pointerout</h2>
+ <h4>Test Description: This test checks if pointerout event triggers for pen. Place your pen over the black rectangle and then pull the pen out of the digitizer's detectable range. </h4>
+ <p>Note: this test is for devices that support hover - for pen only</p>
+ <div id="target0"></div>
+ <script>
+ var test_pointerout = async_test("pointerout event received");
+ // showPointerTypes is defined in pointerevent_support.js
+ // Requirements: the callback function will reference the test_pointerEvent object and
+ // will fail unless the async_test is created with the var name "test_pointerEvent".
+ add_completion_callback(showPointerTypes);
+
+ var eventTested = false;
+ var isPointerupReceived = false;
+ var detected_pointertypes = {};
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ // When a pen stylus leaves the hover range detectable by the digitizer the pointerout event must be dispatched.
+ // TA: 7.2
+ on_event(target0, "pointerout", function (event) {
+ detected_pointertypes[event.pointerType] = true;
+ if(event.pointerType == 'pen') {
+ if (eventTested == false) {
+ eventTested = true;
+ test_pointerout.done();
+ }
+ }
+ else {
+ test_pointerout.step(function() {
+ assert_true(false,
+ "you have to use pen for this test");
+ }, "you have to use pen for this test");
+ }
+ });
+ }
+
+ </script>
+ <h1>Pointer Events pointerout tests</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html
new file mode 100644
index 0000000000..3386fafb5a
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html
@@ -0,0 +1,137 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms</title>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+ <link rel="author" title="Microsoft" href="http://www.microsoft.com/"/>
+ <meta name="assert" content="After invoking the releasePointerCapture method on an element, subsequent events for the specified pointer must follow normal hit testing mechanisms for determining the event target"/>
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script type="text/javascript">
+ var test_pointerEvent;
+ var detected_pointertypes = {};
+ var captured_event = null;
+ var test_done = false;
+ var overEnterEventsFail = false;
+ var outLeaveEventsFail = false;
+ var f_gotPointerCapture = false;
+ var f_lostPointerCapture = false;
+
+ function resetTestState() {
+ captured_event = null;
+ test_done = false;
+ overEnterEventsFail = false;
+ outLeaveEventsFail = false;
+ f_gotPointerCapture = false;
+ f_lostPointerCapture = false;
+ }
+
+ function listenerEventHandler(event) {
+ if (test_done)
+ return;
+ detected_pointertypes[event.pointerType] = true;
+ if (event.type == "gotpointercapture") {
+ f_gotPointerCapture = true;
+ check_PointerEvent(event);
+ }
+ else if (event.type == "lostpointercapture") {
+ f_lostPointerCapture = true;
+ f_gotPointerCapture = false;
+ check_PointerEvent(event);
+ }
+ else if(event.type == "pointerover" || event.type == "pointerenter") {
+ if(captured_event && !overEnterEventsFail) {
+ test(function() {
+ assert_false(f_gotPointerCapture, "pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it.");
+ }, expectedPointerType + " pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it.");
+ overEnterEventsFail = true;
+ }
+ }
+ else if(event.type == "pointerout" || event.type == "pointerleave") {
+ if(!outLeaveEventsFail) {
+ test(function() {
+ assert_true(f_lostPointerCapture, "pointerout/leave should not be received unless the target just lost the capture.");
+ }, expectedPointerType + " pointerout/leave should not be received unless the target just lost the capture.");
+ outLeaveEventsFail = true;
+ }
+ }
+ else if (event.pointerId == captured_event.pointerId) {
+ if (f_gotPointerCapture && event.type == "pointermove") {
+ // on first event received for capture, release capture
+ listener.releasePointerCapture(event.pointerId);
+ }
+ else {
+ // if any other events are received after releaseCapture, then the test fails
+ test(function () {
+ assert_unreached(event.target.id + "-" + event.type + " should be handled by target element handler");
+ }, expectedPointerType + " No other events should be recieved by capturing node after release");
+ }
+ }
+ }
+
+ function targetEventHandler(event) {
+ if (test_done)
+ return;
+ if (f_gotPointerCapture) {
+ if(event.type != "pointerout" && event.type != "pointerleave") {
+ test(function () {
+ assert_unreached("The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". ");
+ }, expectedPointerType + " The target element should not receive any events while capture is active");
+ }
+ }
+
+ if (event.type == "pointerdown") {
+ // pointerdown event received will be used to capture events.
+ listener.setPointerCapture(event.pointerId);
+ captured_event = event;
+ }
+
+ if (f_lostPointerCapture) {
+ test_pointerEvent.step(function () {
+ assert_equals(event.pointerId, captured_event.pointerId, "pointerID is same for event captured and after release");
+ });
+ if (event.type == "pointerup") {
+ test_done = true;
+ test_pointerEvent.done(); // complete test
+ }
+ }
+ }
+
+ function run() {
+ test_pointerEvent = setup_pointerevent_test("got/lost pointercapture: subsequent events to target", ALL_POINTERS); // set up test harness
+ var listener = document.getElementById("listener");
+ var target0 = document.getElementById("target0");
+ target0.style.touchAction = "none";
+
+ // target0 and listener - handle all events
+ for (var i = 0; i < All_Pointer_Events.length; i++) {
+ on_event(target0, All_Pointer_Events[i], targetEventHandler);
+ on_event(listener, All_Pointer_Events[i], listenerEventHandler);
+ }
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h2 id="pointerTypeDescription"></h2>
+ <div id="listener"></div>
+ <h1>Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms</h1>
+ <h4>
+ Test Description:
+ Use your pointer and press down in the black box. Then move around in the box and release your pointer.
+ After invoking the releasePointerCapture method on an element, subsequent events for the specified
+ pointer must follow normal hit testing mechanisms for determining the event target.
+ </h4>
+ <br />
+ <div id="target0">
+ </div>
+ <div id="complete-notice">
+ <p>Test complete: Scroll to Summary to view Pass/Fail Results.</p>
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>Refresh the page to run the tests again with a different pointer type.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html
new file mode 100644
index 0000000000..105e3b5a97
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Release capture on pointercancel</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ </head>
+ <body class="scrollable">
+ <h1>Pointer Events Capture Test - release capture on pointercancel</h1>
+ <h4>
+ Test Description: This test checks if setCapture/releaseCapture functions works properly. Complete the following actions:
+ <ol>
+ <li> Touch black rectangle and do not release your touch
+ <li> Move your touch to scroll the page. "lostpointercapture" should be logged inside of the black rectangle immediately after "pointercancel"
+ </ol>
+ </h4>
+ Test passes if the proper behavior of the events is observed.
+ <div id="target0" style="background:black; color:white"></div>
+
+ <script type='text/javascript'>
+ var pointercancelGot = false;
+ var count=0;
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("pointer capture is released on pointercancel");
+
+ var target0 = document.getElementById('target0');
+
+ add_completion_callback(showPointerTypes);
+
+ window.onload = function() {
+ on_event(target0, 'pointerdown', function(e) {
+ detected_pointertypes[e.pointerType] = true;
+ test_pointerEvent.step(function () {
+ assert_equals(e.pointerType, "touch", "Test should be run using a touch as input");
+ });
+ isPointerCapture = true;
+ sPointerCapture(e);
+ pointercancelGot = false;
+ });
+
+ on_event(target0, 'gotpointercapture', function(e) {
+ log("gotpointercapture", document.getElementById('target0'));
+ });
+
+ // If the setPointerCapture method has been invoked on the pointer specified by pointerId, and the releasePointerCapture method has not been invoked, a lostpointercapture event must be dispatched to the element on which the setPointerCapture method was invoked. Furthermore, subsequent events for the specified pointer must follow normal hit testing mechanisms for determining the event target.
+ // TA: 4.4
+ on_event(target0, 'lostpointercapture', function(e) {
+ log("lostpointercapture", document.getElementById('target0'));
+ test_pointerEvent.step(function () {
+ assert_true(pointercancelGot, "pointercancel was received before lostpointercapture");
+ });
+ test_pointerEvent.done();
+ });
+
+ on_event(target0, 'pointercancel', function(e) {
+ log("pointercancel", target0);
+ pointercancelGot = true;
+ });
+ }
+ </script>
+ <h1>Pointer Events Capture Test</h1>
+ <div id="complete-notice">
+ <p>Test complete: Scroll to Summary to view Pass/Fail Results.</p>
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_pointerup_touch.html b/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_pointerup_touch.html
new file mode 100644
index 0000000000..ce730492b4
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_releasepointercapture_pointerup_touch.html
@@ -0,0 +1,102 @@
+<!doctype html>
+<html>
+ <head>
+ <title>releasePointerCapture on pointerup</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="pointerevent_support.js"></script>
+ </head>
+ <body class="scrollable">
+ <h1>Pointer Events Capture Test - releasePointerCapture on pointerup</h1>
+ <h4>
+ Test Description: This test checks if releaseCapture works properly on pointer up. Complete the following actions:
+ <ol>
+ <li> Touch black rectangle and do not release your touch
+ <li> Move and release your touch anywhere over the document
+ </ol>
+ </h4>
+ Test passes if the proper behavior of the events is observed.
+ <div id="target0" style="background:black; color:white"></div>
+
+ <script type='text/javascript'>
+ var pointerupGot = false;
+ var count=0;
+ var event_log = [];
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("releasePointerCapture on pointerup");
+
+ var target0 = document.getElementById('target0');
+ var actions_promise;
+
+ add_completion_callback(end_of_test);
+ function end_of_test() {
+ showLoggedEvents();
+ showPointerTypes();
+ }
+
+ window.onload = function() {
+ on_event(target0, 'pointerdown', function(e) {
+ detected_pointertypes[e.pointerType] = true;
+ test_pointerEvent.step(function () {
+ assert_equals(e.pointerType, "touch", "Test should be run using a touch as input");
+ });
+ sPointerCapture(e);
+ pointerupGot = false;
+ });
+
+ on_event(target0, 'gotpointercapture', function(e) {
+ event_log.push('gotpointercapture@target0');
+ });
+
+ on_event(target0, 'lostpointercapture', function(e) {
+ event_log.push('lostpointercapture@target0');
+ test_pointerEvent.step(function () {
+ assert_true(pointerupGot, "pointerup was received before lostpointercapture");
+ });
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test_pointerEvent.done();
+ });
+ });
+
+ on_event(target0, 'pointerup', function(e) {
+ event_log.push('pointerup@target0');
+ try {
+ target0.releasePointerCapture(e.pointerId);
+ } catch(error) {
+ test_pointerEvent.step(function () {
+ assert_unreached("target0.releasePointerCapture should not throw");
+ });
+ }
+ pointerupGot = true;
+ });
+
+ on_event(target0, 'touchmove', function(e) {
+ // To prevent pointercancel firing.
+ e.preventDefault();
+ });
+
+ on_event(target0, 'pointercancel', function(e) {
+ test_pointerEvent.step(function () {
+ assert_unreached("target0 shouldn't receive pointercancel");
+ });
+ });
+
+ // Inject touch inputs.
+ actions_promise = touchScrollInTarget(target0, 'down');
+ }
+ </script>
+ <h1>Pointer Events Capture Test</h1>
+ <div id="complete-notice">
+ <p>Test complete: Scroll to Summary to view Pass/Fail Results.</p>
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>The following events were logged: <span id="event-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_click-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_click-manual.html
new file mode 100644
index 0000000000..274f9a435b
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_click-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Event: Event sequence at implicit release on click</title>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+ <link rel="author" title="Google" href="http://www.google.com "/>
+ <meta name="assert" content="When a captured pointer is implicitly released after a click, the boundary events should follow the lostpointercapture event."/>
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script type="text/javascript">
+ var detected_pointertypes = {};
+ var event_log = [];
+ var start_logging = false;
+
+ function resetTestState() {
+ detected_eventTypes = {};
+ event_log = [];
+ start_logging = false;
+ }
+
+ function run() {
+ var test_pointer_event = setup_pointerevent_test("Event sequence at implicit release on click", ALL_POINTERS);
+
+ on_event(document.getElementById("done"), "click", function() {
+ test_pointer_event.step(function () {
+ var expected_events = "pointerup, lostpointercapture, pointerout, pointerleave";
+ assert_equals(event_log.join(", "), expected_events);
+ });
+ test_pointer_event.done();
+ });
+
+ var target = document.getElementById("target");
+
+ All_Pointer_Events.forEach(function(eventName) {
+ on_event(target, eventName, function (event) {
+ detected_pointertypes[event.pointerType] = true;
+
+ if (event.type == "pointerdown") {
+ event.target.setPointerCapture(event.pointerId);
+
+ } else if (event.type == "gotpointercapture") {
+ start_logging = true;
+
+ } else if (event.type != "pointermove" && start_logging) {
+ event_log.push(event.type);
+ }
+ });
+ });
+ }
+ </script>
+ <style>
+ #target {
+ margin: 20px;
+ background-color: black;
+ }
+
+ #done {
+ margin: 20px;
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Event: Event sequence at implicit release on click<h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ When a captured pointer is implicitly released after a click, the boundary events should follow the lostpointercapture event.
+ </h4>
+ <ol>
+ <li>Click or tap on Black.</li>
+ <li>Click or tap on Green.</li>
+ </ol>
+ <div id="target"></div>
+ <div id="done"></div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>The following events were logged: <span id="event-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.html
new file mode 100644
index 0000000000..7b8e39b94d
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_sequence_at_implicit_release_on_drag-manual.html
@@ -0,0 +1,84 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Event: Event sequence at implicit release on drag</title>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+ <link rel="author" title="Google" href="http://www.google.com "/>
+ <meta name="assert" content="When a captured pointer is implicitly released after a drag, the boundary events should follow the lostpointercapture event."/>
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script type="text/javascript" src="pointerevent_support.js"></script>
+ <script type="text/javascript">
+ var detected_pointertypes = {};
+ var event_log = [];
+ var start_logging = false;
+
+ function resetTestState() {
+ detected_eventTypes = {};
+ event_log = [];
+ start_logging = false;
+ }
+
+ function run() {
+ var test_pointer_event = setup_pointerevent_test("Event sequence at implicit release on drag", ["touch"]);
+
+ on_event(document.getElementById("done"), "click", function() {
+ test_pointer_event.step(function () {
+ var expected_events = "pointercancel, lostpointercapture, pointerout, pointerleave";
+ assert_equals(event_log.join(", "), expected_events);
+ });
+ test_pointer_event.done();
+ });
+
+ var target = document.getElementById("target");
+
+ All_Pointer_Events.forEach(function(eventName) {
+ on_event(target, eventName, function (event) {
+ detected_pointertypes[event.pointerType] = true;
+
+ if (event.type == "pointerdown") {
+ event.target.setPointerCapture(event.pointerId);
+
+ } else if (event.type == "gotpointercapture") {
+ start_logging = true;
+
+ } else if (event.type != "pointermove" && start_logging) {
+ event_log.push(event.type);
+ }
+ });
+ });
+ }
+ </script>
+ <style>
+ #target {
+ margin: 20px;
+ background-color: black;
+ touch-action: auto;
+ }
+
+ #done {
+ margin: 20px;
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Event: Event sequence at implicit release on drag<h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ When a captured pointer is implicitly released after a drag, the boundary events should follow the lostpointercapture event.
+ </h4>
+ <ol>
+ <li>Drag quickly down starting on Black.</li>
+ <li>Click or tap on Green.</li>
+ </ol>
+ <div id="target"></div>
+ <div id="done"></div>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>The following events were logged: <span id="event-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_setpointercapture_pointerup_touch.html b/dom/events/test/pointerevents/wpt/pointerevent_setpointercapture_pointerup_touch.html
new file mode 100644
index 0000000000..8122251a71
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_setpointercapture_pointerup_touch.html
@@ -0,0 +1,102 @@
+<!doctype html>
+<html>
+ <head>
+ <title>setPointerCapture on pointerup</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="pointerevent_support.js"></script>
+ </head>
+ <body class="scrollable">
+ <h1>Pointer Events Capture Test - setPointerCapture on pointerup</h1>
+ <h4>
+ Test Description: This test checks if releaseCapture works properly on pointer up. Complete the following actions:
+ <ol>
+ <li> Touch black rectangle
+ <li> Release your touch
+ </ol>
+ </h4>
+ Test passes if the proper behavior of the events is observed.
+ <div id="target0" style="background:black; color:white"></div>
+
+ <script type='text/javascript'>
+ var count=0;
+ var event_log = [];
+ var detected_pointertypes = {};
+ var test_pointerEvent = async_test("setPointerCapture on pointerup");
+
+ var target0 = document.getElementById('target0');
+ var actions_promise;
+
+ add_completion_callback(end_of_test);
+ function end_of_test() {
+ showLoggedEvents();
+ showPointerTypes();
+ }
+
+ window.onload = function() {
+ on_event(target0, 'pointerdown', function(e) {
+ detected_pointertypes[e.pointerType] = true;
+ event_log.push('pointerdown@target0');
+ test_pointerEvent.step(function () {
+ assert_equals(e.pointerType, "touch", "Test should be run using a touch as input");
+ });
+ });
+
+ on_event(target0, 'gotpointercapture', function(e) {
+ event_log.push('gotpointercapture@target0');
+ });
+
+ on_event(target0, 'lostpointercapture', function(e) {
+ event_log.push('lostpointercapture@target0');
+ });
+
+ on_event(target0, 'pointerup', function(e) {
+ event_log.push('pointerup@target0');
+ try {
+ target0.setPointerCapture(e.pointerId);
+ } catch(error) {
+ test_pointerEvent.step(function () {
+ assert_unreached("target0.setPointerCapture should not throw");
+ });
+ }
+ // Make sure the test finishes after all the input actions are completed.
+ actions_promise.then( () => {
+ test_pointerEvent.done();
+ });
+ });
+
+ on_event(target0, 'touchmove', function(e) {
+ // To prevent pointercancel firing.
+ e.preventDefault();
+ });
+
+ on_event(target0, 'pointercancel', function(e) {
+ test_pointerEvent.step(function () {
+ assert_unreached("target0 shouldn't receive pointercancel");
+ });
+ });
+
+ // Inject touch inputs.
+ actions_promise = new test_driver.Actions()
+ .addPointer("touchPointer1", "touch")
+ .pointerMove(10, 10, {origin: target0})
+ .pointerDown()
+ .pause(100)
+ .pointerUp()
+ .send();
+ }
+ </script>
+ <h1>Pointer Events Capture Test</h1>
+ <div id="complete-notice">
+ <p>Test complete: Scroll to Summary to view Pass/Fail Results.</p>
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ <p>The following events were logged: <span id="event-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_styles.css b/dom/events/test/pointerevents/wpt/pointerevent_styles.css
new file mode 100644
index 0000000000..1ee3b0b396
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_styles.css
@@ -0,0 +1,112 @@
+#innerFrame {
+position: absolute;
+top: 300px;
+left: 200px;
+height: 100px;
+width: 100px;
+}
+
+.spacer {
+height: 100px;
+}
+
+#square1 {
+top: 330px;
+left: 150px;
+background: black;
+}
+
+#square2 {
+top: 50px;
+left: 30px;
+visibility: hidden;
+background: red;
+}
+
+.square {
+height: 20px;
+width: 20px;
+position: absolute;
+padding: 0px;
+}
+
+#target0 {
+background: black;
+color: white;
+white-space: nowrap;
+overflow-y: auto;
+overflow-x: auto;
+}
+
+#target1 {
+background: purple;
+color: white;
+white-space: nowrap;
+overflow-y: auto;
+overflow-x: auto;
+}
+
+#scrollTarget {
+ background: darkblue;
+}
+
+.touchActionNone {
+touch-action: none;
+}
+
+#innerframe {
+width: 90%;
+margin: 10px;
+margin-left: 10%;
+height: 200px;
+}
+
+.scroller {
+width: 700px;
+height: 430px;
+margin: 20px;
+overflow: auto;
+background: black;
+}
+
+.scroller > div {
+height: 1000px;
+width: 1000px;
+color: white;
+}
+
+.scroller > div div {
+height: 100%;
+width: 100%;
+color: white;
+}
+
+div {
+margin: 0em;
+padding: 2em;
+}
+
+#complete-notice {
+background: #afa;
+border: 1px solid #0a0;
+display: none;
+}
+
+#pointertype-log {
+font-weight: bold;
+}
+
+#event-log {
+font-weight: bold;
+}
+
+#listener {
+background: orange;
+border: 1px solid orange;
+position: absolute;
+top: -100px;
+}
+
+body.scrollable {
+min-height: 5000px;
+}
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_support.js b/dom/events/test/pointerevents/wpt/pointerevent_support.js
new file mode 100644
index 0000000000..4b8c83cbe0
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_support.js
@@ -0,0 +1,333 @@
+var All_Pointer_Events = [
+ "pointerdown",
+ "pointerup",
+ "pointercancel",
+ "pointermove",
+ "pointerover",
+ "pointerout",
+ "pointerenter",
+ "pointerleave",
+ "gotpointercapture",
+ "lostpointercapture",
+];
+
+// Check for conformance to PointerEvent interface
+// TA: 1.1, 1.2, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11, 1.12, 1.13
+function check_PointerEvent(event, testNamePrefix) {
+ if (testNamePrefix === undefined) {
+ testNamePrefix = "";
+ }
+
+ // Use expectedPointerType if set otherwise just use the incoming event pointerType in the test name.
+ var pointerTestName =
+ testNamePrefix +
+ " " +
+ (expectedPointerType == null ? event.pointerType : expectedPointerType) +
+ " " +
+ event.type;
+
+ if (expectedPointerType != null) {
+ test(function() {
+ assert_equals(
+ event.pointerType,
+ expectedPointerType,
+ "pointerType should be the one specified in the test page."
+ );
+ }, pointerTestName + " event pointerType is correct.");
+ }
+
+ test(function() {
+ assert_true(
+ event instanceof event.target.ownerDocument.defaultView.PointerEvent,
+ "event is a PointerEvent event"
+ );
+ }, pointerTestName + " event is a PointerEvent event");
+
+ // Check attributes for conformance to WebIDL:
+ // * attribute exists
+ // * has proper type
+ // * if the attribute is "readonly", it cannot be changed
+ // TA: 1.1, 1.2
+ var idl_type_check = {
+ long(v) {
+ return typeof v === "number" && Math.round(v) === v;
+ },
+ float(v) {
+ return typeof v === "number";
+ },
+ string(v) {
+ return typeof v === "string";
+ },
+ boolean(v) {
+ return typeof v === "boolean";
+ },
+ };
+ [
+ ["readonly", "long", "pointerId"],
+ ["readonly", "float", "width"],
+ ["readonly", "float", "height"],
+ ["readonly", "float", "pressure"],
+ ["readonly", "long", "tiltX"],
+ ["readonly", "long", "tiltY"],
+ ["readonly", "string", "pointerType"],
+ ["readonly", "boolean", "isPrimary"],
+ ["readonly", "long", "detail", 0],
+ ].forEach(function(attr) {
+ var readonly = attr[0];
+ var type = attr[1];
+ var name = attr[2];
+ var value = attr[3];
+
+ // existence check
+ test(function() {
+ assert_true(
+ name in event,
+ name + " attribute in " + event.type + " event"
+ );
+ }, pointerTestName + "." + name + " attribute exists");
+
+ // readonly check
+ if (readonly === "readonly") {
+ test(function() {
+ assert_readonly(
+ event.type,
+ name,
+ event.type + "." + name + " cannot be changed"
+ );
+ }, pointerTestName + "." + name + " is readonly");
+ }
+
+ // type check
+ test(function() {
+ assert_true(
+ idl_type_check[type](event[name]),
+ name + " attribute of type " + type
+ );
+ }, pointerTestName +
+ "." +
+ name +
+ " IDL type " +
+ type +
+ " (JS type was " +
+ typeof event[name] +
+ ")");
+
+ // value check if defined
+ if (value != undefined) {
+ test(function() {
+ assert_equals(event[name], value, name + " attribute value");
+ }, pointerTestName + "." + name + " value is " + value + ".");
+ }
+ });
+
+ // Check the pressure value
+ // TA: 1.6, 1.7, 1.8
+ test(function() {
+ // TA: 1.6
+ assert_greater_than_equal(
+ event.pressure,
+ 0,
+ "pressure is greater than or equal to 0"
+ );
+ assert_less_than_equal(
+ event.pressure,
+ 1,
+ "pressure is less than or equal to 1"
+ );
+
+ if (event.type === "pointerup") {
+ assert_equals(event.pressure, 0, "pressure is 0 during pointerup");
+ }
+
+ // TA: 1.7, 1.8
+ if (event.pointerType === "mouse") {
+ if (event.buttons === 0) {
+ assert_equals(
+ event.pressure,
+ 0,
+ "pressure is 0 for mouse with no buttons pressed"
+ );
+ } else {
+ assert_equals(
+ event.pressure,
+ 0.5,
+ "pressure is 0.5 for mouse with a button pressed"
+ );
+ }
+ }
+ }, pointerTestName + ".pressure value is valid");
+
+ // Check mouse-specific properties
+ if (event.pointerType === "mouse") {
+ // TA: 1.9, 1.10, 1.13
+ test(function() {
+ assert_equals(event.width, 1, "width of mouse should be 1");
+ assert_equals(event.height, 1, "height of mouse should be 1");
+ assert_equals(event.tiltX, 0, event.type + ".tiltX is 0 for mouse");
+ assert_equals(event.tiltY, 0, event.type + ".tiltY is 0 for mouse");
+ assert_true(event.isPrimary, event.type + ".isPrimary is true for mouse");
+ }, pointerTestName + " properties for pointerType = mouse");
+ // Check properties for pointers other than mouse
+ }
+}
+
+function showPointerTypes() {
+ var complete_notice = document.getElementById("complete-notice");
+ var pointertype_log = document.getElementById("pointertype-log");
+ var pointertypes = Object.keys(detected_pointertypes);
+ pointertype_log.innerHTML = pointertypes.length
+ ? pointertypes.join(",")
+ : "(none)";
+ complete_notice.style.display = "block";
+}
+
+function showLoggedEvents() {
+ var event_log_elem = document.getElementById("event-log");
+ event_log_elem.innerHTML = event_log.length ? event_log.join(", ") : "(none)";
+
+ var complete_notice = document.getElementById("complete-notice");
+ complete_notice.style.display = "block";
+}
+
+function log(msg, el) {
+ if (++count > 10) {
+ count = 0;
+ el.innerHTML = " ";
+ }
+ el.innerHTML = msg + "; " + el.innerHTML;
+}
+
+function failOnScroll() {
+ assert_true(false, "scroll received while shouldn't");
+}
+
+function updateDescriptionNextStep() {
+ document.getElementById("desc").innerHTML =
+ "Test Description: Try to scroll text RIGHT.";
+}
+
+function updateDescriptionComplete() {
+ document.getElementById("desc").innerHTML = "Test Description: Test complete";
+}
+
+function updateDescriptionSecondStepTouchActionElement(
+ target,
+ scrollReturnInterval
+) {
+ window.setTimeout(function() {
+ objectScroller(target, "up", 0);
+ }, scrollReturnInterval);
+ document.getElementById("desc").innerHTML =
+ "Test Description: Try to scroll element RIGHT moving your outside of the red border";
+}
+
+function updateDescriptionThirdStepTouchActionElement(
+ target,
+ scrollReturnInterval,
+ callback = null
+) {
+ window.setTimeout(function() {
+ objectScroller(target, "left", 0);
+ if (callback) {
+ callback();
+ }
+ }, scrollReturnInterval);
+ document.getElementById("desc").innerHTML =
+ "Test Description: Try to scroll element DOWN then RIGHT starting your touch inside of the element. Then tap complete button";
+}
+
+function updateDescriptionFourthStepTouchActionElement(
+ target,
+ scrollReturnInterval
+) {
+ document.getElementById("desc").innerHTML =
+ "Test Description: Try to scroll element RIGHT starting your touch inside of the element";
+}
+
+function objectScroller(target, direction, value) {
+ if (direction == "up") {
+ target.scrollTop = 0;
+ } else if (direction == "left") {
+ target.scrollLeft = 0;
+ }
+}
+
+function sPointerCapture(e) {
+ try {
+ target0.setPointerCapture(e.pointerId);
+ } catch (ex) {}
+}
+
+function rPointerCapture(e) {
+ try {
+ captureButton.value = "Set Capture";
+ target0.releasePointerCapture(e.pointerId);
+ } catch (ex) {}
+}
+
+var globalPointerEventTest = null;
+var expectedPointerType = null;
+const ALL_POINTERS = ["mouse", "touch", "pen"];
+const HOVERABLE_POINTERS = ["mouse", "pen"];
+const NOHOVER_POINTERS = ["touch"];
+
+function MultiPointerTypeTest(testName, types) {
+ this.testName = testName;
+ this.types = types;
+ this.currentTypeIndex = 0;
+ this.currentTest = null;
+ this.createNextTest();
+}
+
+MultiPointerTypeTest.prototype.skip = function() {
+ var prevTest = this.currentTest;
+ this.createNextTest();
+ prevTest.timeout();
+};
+
+MultiPointerTypeTest.prototype.done = function() {
+ var prevTest = this.currentTest;
+ this.createNextTest();
+ if (prevTest != null) {
+ prevTest.done();
+ }
+};
+
+MultiPointerTypeTest.prototype.step = function(stepFunction) {
+ this.currentTest.step(stepFunction);
+};
+
+MultiPointerTypeTest.prototype.createNextTest = function() {
+ if (this.currentTypeIndex < this.types.length) {
+ var pointerTypeDescription = document.getElementById(
+ "pointerTypeDescription"
+ );
+ document.getElementById("pointerTypeDescription").innerHTML =
+ "Follow the test instructions with <span style='color: red'>" +
+ this.types[this.currentTypeIndex] +
+ "</span>. If you don't have the device <a href='javascript:;' onclick='globalPointerEventTest.skip()'>skip it</a>.";
+ this.currentTest = async_test(
+ this.types[this.currentTypeIndex] + " " + this.testName
+ );
+ expectedPointerType = this.types[this.currentTypeIndex];
+ this.currentTypeIndex++;
+ } else {
+ document.getElementById("pointerTypeDescription").innerHTML = "";
+ }
+ resetTestState();
+};
+
+function setup_pointerevent_test(testName, supportedPointerTypes) {
+ return (globalPointerEventTest = new MultiPointerTypeTest(
+ testName,
+ supportedPointerTypes
+ ));
+}
+
+function checkPointerEventType(event) {
+ assert_equals(
+ event.pointerType,
+ expectedPointerType,
+ "pointerType should be the same as the requested device."
+ );
+}
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-auto-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-auto-css_touch-manual.html
new file mode 100644
index 0000000000..f5e9d12c35
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-auto-css_touch-manual.html
@@ -0,0 +1,129 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: auto</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: auto;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(target0, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(event.pointerType, "touch", "wrong pointer type was detected: ");
+ });
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction.step(function () {
+ yScrollIsReceived = true;
+ assert_true(true, "y-scroll received.");
+ });
+ updateDescriptionNextStep();
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction.done();
+ updateDescriptionComplete();
+ }
+ });
+ }
+ </script>
+ <h1>touch-action: auto</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-button-test_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-button-test_touch-manual.html
new file mode 100644
index 0000000000..c7c5d9a440
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-button-test_touch-manual.html
@@ -0,0 +1,110 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Button touch-action test</title>
+ <meta name="assert" content="TA15.11 -The touch-action CSS property applies to button elements.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ height: 150px;
+ width: 200px;
+ overflow-y: auto;
+ background: black;
+ padding: 100px;
+ position: relative;
+ }
+ button {
+ touch-action: none;
+ width: 350px;
+ height: 350px;
+ border: 2px solid red;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h2>Pointer Events touch-action attribute support</h2>
+ <h4 id="desc">Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.</h4>
+ <p>Note: this test is for touch only</p>
+ <div id="target0">
+ <button id="testButton">Test Button</button>
+ </div>
+ <br>
+ <input type="button" id="btnComplete" value="Complete test">
+
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+ var scrollReturnInterval = 1000;
+ var isFirstPart = true;
+ setup({ explicit_timeout: true });
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ //TA 15.11
+ var test_touchaction_div = async_test("touch-action attribute test out of element");
+ var test_touchaction_button = async_test("touch-action attribute test in element");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(btnComplete, 'click', function(event) {
+ test_touchaction_button.step(function() {
+ assert_equals(target0.scrollLeft, 0, "button scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "button scroll y offset should be 0 in the end of the test");
+ assert_true(xScrollIsReceived && yScrollIsReceived, "target0 x and y scroll offsets should be greater than 0 after first two interactions (outside red border) respectively");
+ });
+ test_touchaction_button.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(btnComplete, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ if(isFirstPart) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction_div.step(function () {
+ yScrollIsReceived = true;
+ });
+ updateDescriptionSecondStepTouchActionElement(target0, scrollReturnInterval);
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction_div.done();
+ updateDescriptionThirdStepTouchActionElement(target0, scrollReturnInterval, function () {
+ setTimeout(function() {
+ isFirstPart = false;
+ }, scrollReturnInterval); // avoid immediate triggering while scroll is still being performed
+ });
+ }
+ }
+ else {
+ test_touchaction_button.step(failOnScroll, "scroll received while shouldn't");
+ }
+ });
+ }
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-illegal.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-illegal.html
new file mode 100644
index 0000000000..5fe6179840
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-illegal.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: illegal</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 50px;
+ touch-action: pan-x none;
+ }
+ #target1 {
+ width: 700px;
+ height: 50px;
+ background: black;
+ margin-top: 5px;
+ touch-action: pan-y none;
+ }
+ #target2 {
+ width: 700px;
+ height: 50px;
+ background: black;
+ margin-top: 5px;
+ touch-action: auto none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Test will automatically check behaviour of following combinations: 'pan-x none', 'pan-y none', 'auto none'</h4>
+ <div id="target0"></div>
+ <div id="target1"></div>
+ <div id="target2"></div>
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ setup({ explicit_done: true });
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById('target0');
+ var target1 = document.getElementById('target1');
+ var target2 = document.getElementById('target2');
+
+ test(function() {
+ assert_true(getComputedStyle(target0).touchAction == 'auto', "'pan-x none' is corrected properly");
+ }, "'pan-x none' is corrected properly");
+ test(function() {
+ assert_true(getComputedStyle(target1).touchAction == 'auto', "'pan-y none' is corrected properly");
+ }, "'pan-y none' is corrected properly");
+ test(function() {
+ assert_true(getComputedStyle(target2).touchAction == 'auto', "'auto none' is corrected properly");
+ }, "'auto none' is corrected properly");
+ done();
+ }
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html
new file mode 100644
index 0000000000..dcea283750
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html
@@ -0,0 +1,117 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: parent > child: auto > child: none</title>
+ <meta name="assert" content="TA15.5 - when a user touches an element, the effect of that touch is determined by the value of the touch-action property and the default touch behaviors on the element and its ancestors. Scrollable-Parent, Child: `auto`, Grand-Child: `none`">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ .scroller > div {
+ touch-action: auto;
+ }
+ .scroller > div div {
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT inside blue rectangle. Tap Complete button under the rectangle when done. Expected: no panning.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div class="scroller" id="target0">
+ <div>
+ <div id="scrollTarget">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ </div>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ add_completion_callback(showPointerTypes);
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if touch-action attribute works properly for embedded divs
+ // Scrollable-Parent, Child: `auto`, Grand-Child: `none`
+ // TA: 15.5
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ test_touchaction.step(failOnScroll, "scroll received while touch-action is none");
+ });
+ }
+ </script>
+ <h1>behaviour: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-none_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-none_touch-manual.html
new file mode 100644
index 0000000000..16e42954e5
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-none_touch-manual.html
@@ -0,0 +1,112 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: child: none</title>
+ <meta name="assert" content="TA15.9 - when a user touches an element, the effect of that touch is determined by the value of the touch-action property and the default touch behaviors on the element and its ancestors. Scrollable-Parent, Child: `none`">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ .scroller > div {
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT inside blue rectangle. Tap Complete button under the rectangle when done. Expected: no panning</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div class="scroller" id="target0">
+ <div id="scrollTarget">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ add_completion_callback(showPointerTypes);
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if touch-action attribute works properly for embedded divs
+ //
+ // TA: 15.9
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ test_touchaction.step(failOnScroll, "scroll received while touch-action is none");
+ });
+ }
+ </script>
+ <h1>behaviour: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html
new file mode 100644
index 0000000000..c75d067e44
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html
@@ -0,0 +1,112 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: parent > child: pan-x > child: pan-x</title>
+ <meta name="assert" content="TA15.6 - when a user touches an element, the effect of that touch is determined by the value of the touch-action property and the default touch behaviors on the element and its ancestors. Scrollable-Parent, Child: `pan-x`, Grand-Child: `pan-x`">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ .scroller > div {
+ touch-action: pan-x;
+ }
+ .scroller > div div {
+ touch-action: pan-x;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT inside blue rectangle. Tap Complete button under the rectangle when done. Expected: only pans in x direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div class="scroller" id="target0">
+ <div>
+ <div id="scrollTarget">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ </div>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if touch-action attribute works properly for embedded divs
+ //
+ // TA: 15.6
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_not_equals(target0.scrollLeft, 0, "scroll x offset should not be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>behaviour: pan-x</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html
new file mode 100644
index 0000000000..d420cc56c7
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html
@@ -0,0 +1,117 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: parent > child: pan-x > child: pan-y</title>
+ <meta name="assert" content="TA15.13 - Touch action inherits child 'pan-x' -> child 'pan-y' test">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ .scroller > div {
+ touch-action: pan-x;
+ }
+ .scroller > div div {
+ touch-action: pan-y;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT inside blue rectangle. Tap Complete button under the rectangle when done. Expected: no panning/zooming/etc.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div class="scroller" id="target0">
+ <div>
+ <div id="scrollTarget">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ </div>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ add_completion_callback(showPointerTypes);
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if touch-action attribute works properly for embedded divs
+ // Scrollable-Parent, Child: `pan-x`, Grand-Child: `pan-y`
+ // TA: 15.13
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ test_touchaction.step(failOnScroll, "scroll received while touch-action is none");
+ });
+ }
+ </script>
+ <h1>behaviour: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html
new file mode 100644
index 0000000000..d87d2b3a34
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html
@@ -0,0 +1,133 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: parent: none + two embedded children</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #divParent {
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll text DOWN inside blue rectangle. Wait for description update. Expected: pan enabled</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="divParent">
+ <div class="scroller" id="target0">
+ <div id="scrollTarget">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ </div>
+ </div>
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+
+ add_completion_callback(showPointerTypes);
+ add_completion_callback(enableScrolling);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(target0, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ // Check if touch-action attribute works properly for embedded divs
+ //
+ // TA: 15.
+ on_event(target0, 'scroll', function(event) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ yScrollIsReceived = true;
+ updateDescriptionNextStep();
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction.done();
+ updateDescriptionComplete();
+ }
+ });
+ }
+
+ function enableScrolling() {
+ document.getElementById('divParent').setAttribute('style', 'touch-action: auto');
+ }
+ </script>
+ <h1>behaviour: auto</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_parent-none_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_parent-none_touch-manual.html
new file mode 100644
index 0000000000..5e674a14da
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-inherit_parent-none_touch-manual.html
@@ -0,0 +1,112 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: inherit from parent: none</title>
+ <meta name="assert" content="TA15.8 - when a user touches an element, the effect of that touch is determined by the value of the touch-action property and the default touch behaviors on the element and its ancestors. Scrollable-Parent: `none` Child: `auto`">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ .scroller {
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT inside blue rectangle. Tap Complete button under the rectangle when done. Expected: no panning</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div class="scroller" id="target0">
+ <div id="scrollTarget">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ add_completion_callback(showPointerTypes);
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if touch-action attribute works properly for embedded divs
+ //
+ // TA: 15.8
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ test_touchaction.step(failOnScroll, "scroll received while touch-action is none");
+ });
+ }
+ </script>
+ <h1>behaviour: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-keyboard-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-keyboard-manual.html
new file mode 100644
index 0000000000..3fef3f646f
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-keyboard-manual.html
@@ -0,0 +1,124 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: keyboard</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Press DOWN ARROW key. Wait for description update. Expected: pan enabled</h4>
+ <p>Note: this test is for keyboard only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <script type='text/javascript'>
+
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ target0.focus();
+
+ on_event(target0, 'scroll', function(event) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction.step(function () {
+ yScrollIsReceived = true;
+ assert_true(true, "y-scroll received.");
+ });
+ updateDescriptionNextStepKeyboard();
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction.done();
+ updateDescriptionComplete();
+ }
+ });
+ }
+
+ function updateDescriptionNextStepKeyboard() {
+ document.getElementById('desc').innerHTML = "Test Description: press RIGHT ARROW key.";
+ }
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-mouse-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-mouse-manual.html
new file mode 100644
index 0000000000..fcc8584515
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-mouse-manual.html
@@ -0,0 +1,130 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: mouse</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll text down using mouse (use mouse wheel or click on the scrollbar). Wait for description update.</h4>
+ <p>Note: this test is for mouse only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(target0, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction.step(function () {
+ yScrollIsReceived = true;
+ assert_true(true, "y-scroll received.");
+ });
+ updateDescriptionNextStepMouse();
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction.done();
+ updateDescriptionComplete();
+ }
+ });
+ }
+
+ function updateDescriptionNextStepMouse() {
+ document.getElementById('desc').innerHTML = "Test Description: Try to scroll text right using mouse (use mouse wheel or click on the scrollbar).";
+ }
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-none-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-none-css_touch-manual.html
new file mode 100644
index 0000000000..dec694f3ec
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-none-css_touch-manual.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: none</title>
+ <meta name="assert" content="TA15.2 - With `touch-action: none` on a swiped or click/dragged element, `pointerdown+(optional pointermove)+pointerup` must be dispatched.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: no panning/zooming/etc.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if "touch-action: none" attribute works properly
+ //TA: 15.2
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ test_touchaction.step(failOnScroll, "scroll received while touch-action is none");
+ });
+ }
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-down-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-down-css_touch-manual.html
new file mode 100644
index 0000000000..16e1cb2fab
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-down-css_touch-manual.html
@@ -0,0 +1,114 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: pan-down</title>
+ <meta name="assert" content="TA15.4 - With `touch-action: pan-down` on a swiped or click/dragged element, only panning in the y-axis down direction should be possible.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: pan-down;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element UP (drag down), then RIGHT (drag left), then DOWN (drag up). Tap Complete button under the rectangle when done. Expected: only pans in down direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+ target0.scrollTop = 200;
+
+ var scrollListenerExecuted = false;
+ target0.addEventListener("scroll", function(event) {
+ scrollListenerExecuted = true;
+ assert_greater_than_equal(target0.scrollTop, 200);
+ });
+
+ // Check if "touch-action: pan-down" attribute works properly
+ //TA: 15.4
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_true(scrollListenerExecuted, "scroll listener should have been executed by the end of the test");
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_greater_than(target0.scrollTop, 200, "scroll y offset should be greater than 200 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>touch-action: pan-down</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-left-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-left-css_touch-manual.html
new file mode 100644
index 0000000000..53fd2de138
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-left-css_touch-manual.html
@@ -0,0 +1,114 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: pan-left</title>
+ <meta name="assert" content="TA15.3 - With `touch-action: pan-left` on a swiped or click/dragged element, only panning on the x-axis left direction should be possible.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: pan-left;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN (drag up), then RIGHT (drag left), then LEFT (drag right). Tap Complete button under the rectangle when done. Expected: only pans in left direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+ target0.scrollLeft = 200;
+
+ var scrollListenerExecuted = false;
+ target0.addEventListener("scroll", function(event) {
+ scrollListenerExecuted = true;
+ assert_less_than_equal(target0.scrollLeft, 200);
+ });
+
+ // Check if "touch-action: pan-left" attribute works properly
+ //TA: 15.3
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_true(scrollListenerExecuted, "scroll listener should have been executed by the end of the test");
+ assert_less_than(target0.scrollLeft, 200, "scroll x offset should be less than 200 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>touch-action: pan-left</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-right-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-right-css_touch-manual.html
new file mode 100644
index 0000000000..53bbac65ec
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-right-css_touch-manual.html
@@ -0,0 +1,114 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: pan-right</title>
+ <meta name="assert" content="TA15.3 - With `touch-action: pan-right` on a swiped or click/dragged element, only panning on the x-axis right direction should be possible.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: pan-right;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN (drag up), then LEFT (drag right), then RIGHT (drag left). Tap Complete button under the rectangle when done. Expected: only pans in right direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+ target0.scrollLeft = 200;
+
+ var scrollListenerExecuted = false;
+ target0.addEventListener("scroll", function(event) {
+ scrollListenerExecuted = true;
+ assert_greater_than_equal(target0.scrollLeft, 200);
+ });
+
+ // Check if "touch-action: pan-right" attribute works properly
+ //TA: 15.3
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_true(scrollListenerExecuted, "scroll listener should have been executed by the end of the test");
+ assert_greater_than(target0.scrollLeft, 200, "scroll x offset should be greater than 200 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>touch-action: pan-right</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-up-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-up-css_touch-manual.html
new file mode 100644
index 0000000000..0902700d2d
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-up-css_touch-manual.html
@@ -0,0 +1,114 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: pan-up</title>
+ <meta name="assert" content="TA15.4 - With `touch-action: pan-up` on a swiped or click/dragged element, only panning in the y-axis up direction should be possible.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: pan-up;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN (drag up), then RIGHT (drag left), then UP (drag down). Tap Complete button under the rectangle when done. Expected: only pans in up direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+ target0.scrollTop = 200;
+
+ var scrollListenerExecuted = false;
+ target0.addEventListener("scroll", function(event) {
+ scrollListenerExecuted = true;
+ assert_less_than_equal(target0.scrollTop, 200);
+ });
+
+ // Check if "touch-action: pan-up" attribute works properly
+ //TA: 15.4
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_true(scrollListenerExecuted, "scroll listener should have been executed by the end of the test");
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_less_than(target0.scrollTop, 200, "scroll y offset should be less than 200 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>touch-action: pan-up</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-css_touch-manual.html
new file mode 100644
index 0000000000..e757baec6b
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-css_touch-manual.html
@@ -0,0 +1,106 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: pan-x</title>
+ <meta name="assert" content="TA15.3 - With `touch-action: pan-x` on a swiped or click/dragged element, only panning on the x-axis should be possible.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: pan-x;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in x direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if "touch-action: pan-x" attribute works properly
+ //TA: 15.3
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_not_equals(target0.scrollLeft, 0, "scroll x offset should not be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>touch-action: pan-x</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html
new file mode 100644
index 0000000000..e2a4386b27
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: parent > child: pan-x pan-y > child: pan-y</title>
+ <meta name="assert" content="TA15.17 - Touch action 'pan-x pan-y' 'pan-y' test">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ .scroller > div {
+ touch-action: pan-x pan-y;
+ }
+ .scroller > div div {
+ touch-action: pan-y;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT inside blue rectangle. Tap Complete button under the rectangle when done. Expected: only pans in y direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div class="scroller" id="target0">
+ <div>
+ <div id="scrollTarget">
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ </div>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ add_completion_callback(showPointerTypes);
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if touch-action attribute works properly for embedded divs
+ //
+ // TA: 15.17
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_not_equals(target0.scrollTop, 0, "scroll y offset should not be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>behaviour: pan-y</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y_touch-manual.html
new file mode 100644
index 0000000000..0c900ff740
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-x-pan-y_touch-manual.html
@@ -0,0 +1,126 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: pan-x pan-y</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: pan-x pan-y;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll text DOWN. Wait for description update. Expected: pan enabled</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+
+ var test_touchaction = async_test("touch-action attribute test");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(target0, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction.step(function () {
+ yScrollIsReceived = true;
+ assert_true(true, "y-scroll received.");
+ });
+ updateDescriptionNextStep();
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction.done();
+ updateDescriptionComplete();
+ }
+ });
+ }
+ </script>
+ <h1>touch-action: pan-x pan-y</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-y-css_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-y-css_touch-manual.html
new file mode 100644
index 0000000000..4ad39ecc83
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-pan-y-css_touch-manual.html
@@ -0,0 +1,106 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: pan-y</title>
+ <meta name="assert" content="TA15.4 - With `touch-action: pan-y` on a swiped or click/dragged element, only panning in the y-axis should be possible.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ width: 700px;
+ height: 430px;
+ touch-action: pan-y;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events touch-action attribute support</h1>
+ <h4 id="desc">Test Description: Try to scroll element DOWN then RIGHT. Tap Complete button under the rectangle when done. Expected: only pans in y direction.</h4>
+ <p>Note: this test is for touch-devices only</p>
+ <div id="target0">
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diem
+ nonummy nibh euismod tincidunt ut lacreet dolore magna aliguam erat volutpat.
+ Ut wisis enim ad minim veniam, quis nostrud exerci tution ullamcorper suscipit
+ lobortis nisl ut aliquip ex ea commodo consequat.
+ </p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ <p>Lorem ipsum dolor sit amet...</p>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var test_touchaction = async_test("touch-action attribute test");
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ // Check if "touch-action: pan-y" attribute works properly
+ //TA: 15.4
+ on_event(btnComplete, 'click', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ test_touchaction.step(function() {
+ assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
+ assert_not_equals(target0.scrollTop, 0, "scroll y offset should not be 0 in the end of the test");
+ });
+ test_touchaction.done();
+ updateDescriptionComplete();
+ });
+ }
+ </script>
+ <h1>touch-action: pan-y</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-span-test_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-span-test_touch-manual.html
new file mode 100644
index 0000000000..61f0e8d329
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-span-test_touch-manual.html
@@ -0,0 +1,114 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Span touch-action test</title>
+ <meta name="assert" content="TA15.18 - The touch-action CSS property applies to all elements except non-replaced inline elements."
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ height: 150px;
+ width: 200px;
+ overflow-y: auto;
+ background: black;
+ padding: 100px;
+ position: relative;
+ }
+ #testspan {
+ touch-action: none;
+ font-size: 72pt;
+ padding: 0px 0px 180px 0px;
+ border: 2px solid red;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h2>Pointer Events touch-action attribute support</h2>
+ <h4 id="desc">Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.</h4>
+ <p>Note: this test is for touch only</p>
+ <div id="target0">
+ <span id="testspan">
+ Test span
+ </span>
+ </div>
+ <input type="button" id="btnComplete" value="Complete test">
+
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var failScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+ var scrollReturnInterval = 500;
+ var isFirstPart = true;
+ setup({ explicit_timeout: true });
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ //TA 15.18
+ var test_touchaction_div = async_test("touch-action attribute test out of element");
+ var test_touchaction_span = async_test("touch-action attribute test in element");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(btnComplete, 'click', function(event) {
+ test_touchaction_span.step(function() {
+ assert_not_equals(target0.scrollLeft, 0, "span scroll x offset should not be 0 in the end of the test");
+ assert_not_equals(target0.scrollTop, 0, "span scroll y offset should not be 0 in the end of the test");
+ assert_true(!isFirstPart, "target0 x and y scroll offsets should be greater than 0 after first two interactions (outside red border) respectively");
+ });
+ test_touchaction_span.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(btnComplete, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ if(isFirstPart) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction_div.step(function () {
+ yScrollIsReceived = true;
+ });
+ updateDescriptionSecondStepTouchActionElement(target0, scrollReturnInterval);
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction_div.done();
+ updateDescriptionThirdStepTouchActionElement(target0, scrollReturnInterval, function () {
+ setTimeout(function() {
+ isFirstPart = false;
+ xScr0 = target0.scrollLeft;
+ xScr0 = target0.scrollLeft;
+ xScrollIsReceived = false;
+ yScrollIsReceived = false;
+ }, scrollReturnInterval); // avoid immediate triggering while scroll is still being performed
+ });
+ }
+ }
+ });
+ }
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-svg-test_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-svg-test_touch-manual.html
new file mode 100644
index 0000000000..e9dc9d78ee
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-svg-test_touch-manual.html
@@ -0,0 +1,122 @@
+<!doctype html>
+<html>
+ <head>
+ <title>SVG test</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ height: 350px;
+ width: 300px;
+ overflow-y: auto;
+ background: black;
+ padding: 100px;
+ position: relative;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h2>Pointer Events touch-action attribute support</h2>
+ <h4 id="desc">Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.</h4>
+ <p>Note: this test is for touch only</p>
+ <div id="target0">
+ <svg id="testSvg" width="555" height="555" style="touch-action: none; border: 4px double red;">
+ <circle cx="305" cy="305" r="250" stroke="green" stroke-width="4" fill="yellow" />
+ Sorry, your browser does not support inline SVG.
+ </svg>
+ </div>
+ <br>
+ <input type="button" id="btnComplete" value="Complete test">
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+ var scrollReturnInterval = 1000;
+ var isFirstPart = true;
+ setup({ explicit_timeout: true });
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ var test_touchaction_div = async_test("touch-action attribute test out of SVG");
+ var test_touchaction_svg = async_test("touch-action attribute test in SVG");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(btnComplete, 'click', function(event) {
+ test_touchaction_svg.step(function() {
+ assert_equals(target0.scrollLeft, 0, "SVG scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "SVG scroll y offset should be 0 in the end of the test");
+ });
+ test_touchaction_svg.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(btnComplete, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ if(isFirstPart) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction_div.step(function () {
+ yScrollIsReceived = true;
+ assert_true(true, "y-scroll received.");
+ });
+ updateDescriptionSecondStepSVG();
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction_div.done();
+ updateDescriptionThirdStepSVG();
+ setTimeout(function() {
+ isFirstPart = false;
+ }, 2 * scrollReturnInterval);
+ }
+ }
+ });
+ }
+
+ function updateDescriptionSecondStepSVG() {
+ window.setTimeout(function() {
+ objectScroller(target0, 'up', 0);}
+ , scrollReturnInterval);
+ document.getElementById('desc').innerHTML = "Test Description: Try to scroll element RIGHT moving your touch outside of the red border";
+ }
+
+ function updateDescriptionThirdStepSVG() {
+ window.setTimeout(function() {
+ objectScroller(target0, 'left', 0);}
+ , scrollReturnInterval);
+ document.getElementById('desc').innerHTML = "Test Description: Try to scroll element DOWN then RIGHT starting your touch inside of the circle. Tap Complete button under the rectangle when done";
+ }
+
+ function objectScroller(target, direction, value) {
+ if (direction == 'up') {
+ target.scrollTop = 0;
+ } else if (direction == 'left') {
+ target.scrollLeft = 0;
+ }
+ }
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-table-test_touch-manual.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-table-test_touch-manual.html
new file mode 100644
index 0000000000..17d5a29575
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-table-test_touch-manual.html
@@ -0,0 +1,145 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Table touch-action test</title>
+ <meta name="assert" content="TA15.19 The touch-action CSS property applies to all elements except table rows, row groups, table columns, and column groups.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ #target0 {
+ height: 150px;
+ width: 200px;
+ overflow-y: auto;
+ background: black;
+ padding: 100px;
+ position: relative;
+ }
+ #testtable{
+ color: white;
+ width: 350px;
+ padding: 0px 0px 200px 0px;
+ border: 2px solid green;
+ }
+ .testtd, .testth {
+ border: 2px solid green;
+ height: 80px;
+ }
+ #row1 {
+ touch-action: none;
+ }
+ #cell3 {
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h2>Pointer Events touch-action attribute support</h2>
+ <h4 id="desc">Test Description: Try to scroll element DOWN starting your touch over the 1st Row. Wait for description update.</h4>
+ <p>Note: this test is for touch only</p>
+ <div id="target0">
+ <table id="testtable">
+ <caption>The caption, first row element, and cell 3 have touch-action: none.</caption>
+ <tr id="row1"><th class="testth">Header 1 <td class="testtd">Cell 1 <td class="testtd">Cell 2</tr>
+ <tr id="row2"><th class="testth">Header 2 <td id="cell3" class="testtd">Cell 3 <td class="testtd">Cell 4</tr>
+ <tr id="row3"> <th class="testth">Header 3 <td class="testtd">Cell 5 <td class="testtd"> Cell 6</tr>
+ </table>
+ </div>
+ <br>
+ <input type="button" id="btnComplete" value="Complete test">
+
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+ var xScrollIsReceived = false;
+ var yScrollIsReceived = false;
+ var xScr0, yScr0, xScr1, yScr1;
+ var scrollReturnInterval = 1000;
+ var isFirstPart = true;
+ setup({ explicit_timeout: true });
+ add_completion_callback(showPointerTypes);
+
+ function run() {
+ var target0 = document.getElementById("target0");
+ var btnComplete = document.getElementById("btnComplete");
+
+ //TA 15.19
+ var test_touchaction_cell = async_test("touch-action attribute test on the cell");
+ var test_touchaction_row = async_test("touch-action attribute test on the row");
+
+ xScr0 = target0.scrollLeft;
+ yScr0 = target0.scrollTop;
+
+ on_event(btnComplete, 'click', function(event) {
+ test_touchaction_cell.step(function() {
+ assert_equals(target0.scrollLeft, 0, "table scroll x offset should be 0 in the end of the test");
+ assert_equals(target0.scrollTop, 0, "table scroll y offset should be 0 in the end of the test");
+ assert_true(xScrollIsReceived && yScrollIsReceived, "target0 x and y scroll offsets should be greater than 0 after first two interactions (outside red border) respectively");
+ });
+ test_touchaction_cell.done();
+ updateDescriptionComplete();
+ });
+
+ on_event(btnComplete, 'pointerdown', function(event) {
+ detected_pointertypes[event.pointerType] = true;
+ });
+
+ on_event(target0, 'scroll', function(event) {
+ if(isFirstPart) {
+ xScr1 = target0.scrollLeft;
+ yScr1 = target0.scrollTop;
+
+ if(xScr1 != xScr0) {
+ xScrollIsReceived = true;
+ }
+
+ if(yScr1 != yScr0) {
+ test_touchaction_row.step(function () {
+ yScrollIsReceived = true;
+ });
+ updateDescriptionSecondStepTable(target0, scrollReturnInterval);
+ }
+
+ if(xScrollIsReceived && yScrollIsReceived) {
+ test_touchaction_row.done();
+ updateDescriptionThirdStepTable(target0, scrollReturnInterval, function() {
+ setTimeout(function() {
+ isFirstPart = false;
+ }, scrollReturnInterval); // avoid immediate triggering while scroll is still being performed
+ });
+ }
+ }
+ else {
+ test_touchaction_cell.step(failOnScroll, "scroll received while shouldn't");
+ }
+ });
+ }
+
+ function updateDescriptionSecondStepTable(target, returnInterval, element) {
+ window.setTimeout(function() {
+ objectScroller(target, 'up', 0);
+ }
+ , returnInterval);
+ document.getElementById('desc').innerHTML = "Test Description: Try to scroll element RIGHT staring your touch over the Row 1";
+ }
+
+ function updateDescriptionThirdStepTable(target, returnInterval, callback = null) {
+ window.setTimeout(function() {
+ objectScroller(target, 'left', 0);
+ if (callback) {
+ callback();
+ }
+ }
+ , returnInterval);
+ document.getElementById('desc').innerHTML = "Test Description: Try to scroll element DOWN then RIGHT starting your touch inside of the Cell 3";
+ }
+
+ </script>
+ <h1>touch-action: none</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerevent_touch-action-verification.html b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-verification.html
new file mode 100644
index 0000000000..7800f2c9da
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerevent_touch-action-verification.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html>
+ <head>
+ <title>touch-action: basic verification</title>
+ <meta name="assert" content="TA15.20 - The touch-action CSS property determines whether touch input MAY trigger default behavior supplied by the user agent.
+ auto: The user agent MAY determine any permitted touch behaviors, such as panning and zooming manipulations of the viewport, for touches that begin on the element.
+ none: Touches that begin on the element MUST NOT trigger default touch behaviors.
+ pan-x: The user agent MAY consider touches that begin on the element only for the purposes of horizontally scrolling the element's nearest ancestor with horizontally scrollable content.
+ pan-y: The user agent MAY consider touches that begin on the element only for the purposes of vertically scrolling the element's nearest ancestor with vertically scrollable content.
+ manipulation: The user agent MAY consider touches that begin on the element only for the purposes of scrolling and continuous zooming. Any additional behaviors supported by auto are out of scope for this specification.">
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="pointerevent_support.js"></script>
+ <style>
+ /*
+ Give some rules below something to override in order to test
+ that they really are being parsed
+ */
+ .defnone {
+ touch-action: none;
+ }
+ </style>
+ </head>
+ <body onload="run()">
+ <h2>Pointer Events touch-action attribute support</h2>
+ <h4 id="desc">Test Description: Test will automatically check parsing behaviour of various touch-action combinations.</h4>
+ <script type='text/javascript'>
+ var detected_pointertypes = {};
+
+ setup({ explicit_done: true });
+
+ function run() {
+ var tests = document.querySelectorAll('.test');
+ //TA 15.20
+ for (var i = 0; i < tests.length; i++) {
+ test(function() {
+ var style = window.getComputedStyle(tests[i]);
+ assert_equals(tests[i].attributes.expected.value, style.touchAction);
+ }, tests[i].id);
+ }
+ done();
+ }
+ </script>
+ <h1>touch-action: basic verification</h1>
+ <div id="complete-notice">
+ <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+ </div>
+ <div id="log"></div>
+ <div class="test" id="default" expected="auto"></div>
+ <div class="test defnone" id="stylesheet-none" expected="none"></div>
+ <div class="test defnone" id="explicit-auto" style="touch-action: auto;" expected="auto"></div>
+ <div class="test" id="explicit-pan-x" style="touch-action: pan-x;" expected="pan-x"></div>
+ <div class="test" id="explicit-pan-left" style="touch-action: pan-left;" expected="pan-left"></div>
+ <div class="test" id="explicit-pan-right" style="touch-action: pan-right;" expected="pan-right"></div>
+ <div class="test" id="explicit-pan-y" style="touch-action: pan-y;" expected="pan-y"></div>
+ <div class="test" id="explicit-pan-up" style="touch-action: pan-up;" expected="pan-up"></div>
+ <div class="test" id="explicit-pan-down" style="touch-action: pan-down;" expected="pan-down"></div>
+ <div class="test" id="explicit-pan-x-pan-y" style="touch-action: pan-x pan-y;" expected="pan-x pan-y"></div>
+ <div class="test" id="explicit-pan-y-pan-x" style="touch-action: pan-y pan-x;" expected="pan-x pan-y"></div>
+ <div class="test" id="explicit-pan-left-pan-up" style="touch-action: pan-left pan-up;" expected="pan-left pan-up"></div>
+ <div class="test" id="explicit-pan-left-pan-down" style="touch-action: pan-left pan-down;" expected="pan-left pan-down"></div>
+ <div class="test" id="explicit-pan-right-pan-up" style="touch-action: pan-right pan-up;" expected="pan-right pan-up"></div>
+ <div class="test" id="explicit-pan-right-pan-down" style="touch-action: pan-right pan-down;" expected="pan-right pan-down"></div>
+ <div class="test" id="explicit-pan-up-pan-left" style="touch-action: pan-up pan-left;" expected="pan-left pan-up"></div>
+ <div class="test" id="explicit-pan-up-pan-right" style="touch-action: pan-up pan-right;" expected="pan-right pan-up"></div>
+ <div class="test" id="explicit-pan-down-pan-left" style="touch-action: pan-down pan-left;" expected="pan-left pan-down"></div>
+ <div class="test" id="explicit-pan-down-pan-right" style="touch-action: pan-down pan-right;" expected="pan-right pan-down"></div>
+ <div class="test" id="explicit-manipulation" style="touch-action: manipulation;" expected="manipulation"></div>
+ <div class="test" id="explicit-none" style="touch-action: none;" expected="none"></div>
+ <div class="test" id="explicit-invalid-1" style="touch-action: bogus;" expected="auto"></div>
+ <div class="test defnone" id="explicit-invalid-2" style="touch-action: auto pan-x;" expected="none"></div>
+ <div class="test" id="explicit-invalid-3" style="touch-action: pan-y none;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-4" style="touch-action: pan-x pan-x;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-5" style="touch-action: manipulation pan-x;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-6" style="touch-action: pan-x pan-left;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-7" style="touch-action: auto pan-left;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-8" style="touch-action: none pan-left;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-9" style="touch-action: pan-x pan-right;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-10" style="touch-action: pan-y pan-up;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-11" style="touch-action: pan-y pan-down;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-12" style="touch-action: pan-left pan-right;" expected="auto"></div>
+ <div class="test" id="explicit-invalid-13" style="touch-action: pan-up pan-down;" expected="auto"></div>
+ <div style="touch-action: none;">
+ <div class="test" id="not-inherited" expected="auto"></div>
+ <div class="test" id="inherit" style="touch-action: inherit;" expected="none"></div>
+ </div>
+ <div class="test defnone" id="initial" style="touch-action: initial;" expected="auto"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/pointerlock/pointerevent_movementxy-manual.html b/dom/events/test/pointerevents/wpt/pointerlock/pointerevent_movementxy-manual.html
new file mode 100644
index 0000000000..5b0edd3c61
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerlock/pointerevent_movementxy-manual.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Pointer Events properties tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <!-- Additional helper script for common checks across event types -->
+ <script type="text/javascript" src="../pointerevent_support.js"></script>
+ <style>
+ #testContainer {
+ touch-action: none;
+ user-select: none;
+ position: relative;
+ }
+ #box1 {
+ top: 30px;
+ left: 50px;
+ background: black;
+ }
+ #box2 {
+ top: 70px;
+ left: 250px;
+ background: red;
+ }
+ #innerFrame {
+ top: 10px;
+ left: 100px;
+ }
+ #square2 {
+ visibility: block;
+ }
+ </style>
+ <script>
+ var expectedPointerId = NaN;
+ var startSummation = false;
+ var lastScreenX = 0;
+ var lastScreenY = 0;
+
+ function resetTestState() {
+ startSummation = false;
+ lastScreenX = 0;
+ lastScreenY = 0;
+ }
+
+ function run() {
+ var test_pointerEvent = setup_pointerevent_test("pointerevent attributes", ['mouse', 'touch']);
+
+ [document, document.getElementById('innerFrame').contentDocument].forEach(function(element) {
+ on_event(element, 'pointermove', function (event) {
+ if (startSummation) {
+ test_pointerEvent.step(function() {
+ assert_equals(event.movementX, event.screenX - lastScreenX, "movementX should be the delta between current event's and last event's screenX");
+ assert_equals(event.movementY, event.screenY - lastScreenY, "movementY should be the delta between current event's and last event's screenY");
+ });
+ lastScreenX = event.screenX;
+ lastScreenY = event.screenY;
+ }
+ });
+ });
+ on_event(document.querySelector('#box1'), 'pointerdown', function(event) {
+ event.target.releasePointerCapture(event.pointerId);
+ test_pointerEvent.step(function() {
+ assert_equals(event.pointerType, expectedPointerType, "Use the instructed pointer type.");
+ });
+ startSummation = true;
+ lastScreenX = event.screenX;
+ lastScreenY = event.screenY;
+ });
+ on_event(document.querySelector('#box2'), 'pointerup', function(event) {
+ startSummation = false;
+ test_pointerEvent.done();
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <h1>Pointer Events movementX/Y attribute test</h1>
+ <h2 id="pointerTypeDescription"></h2>
+ <h4>
+ Test Description: This test checks the properties of pointer events that do not support hover.
+ <ol>
+ <li>Press down on the black square.</li>
+ <li>Move your pointer slowly along a straight line to the red square.</li>
+ <li>Release the pointer when you are over the red square.</li>
+ </ol>
+
+ Test passes if the proper behavior of the events is observed.
+ </h4>
+ <div id="testContainer">
+ <div id="box1" class="square"></div>
+ <div id="box2" class="square"></div>
+ <iframe id="innerFrame" src="resources/pointerevent_movementxy-iframe.html"></iframe>
+ </div>
+ <div class="spacer"></div>
+ </body>
+</html>
+
diff --git a/dom/events/test/pointerevents/wpt/pointerlock/resources/pointerevent_movementxy-iframe.html b/dom/events/test/pointerevents/wpt/pointerlock/resources/pointerevent_movementxy-iframe.html
new file mode 100644
index 0000000000..627af3b61c
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/pointerlock/resources/pointerevent_movementxy-iframe.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/resources/pointerevent_attributes_hoverable_pointers-iframe.html b/dom/events/test/pointerevents/wpt/resources/pointerevent_attributes_hoverable_pointers-iframe.html
new file mode 100644
index 0000000000..5e55868282
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/resources/pointerevent_attributes_hoverable_pointers-iframe.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+ </head>
+ <body>
+ <div id="square2" class="square"></div>
+ </body>
+</html>
diff --git a/dom/events/test/pointerevents/wpt/resources/pointerevent_pointerId_scope-iframe.html b/dom/events/test/pointerevents/wpt/resources/pointerevent_pointerId_scope-iframe.html
new file mode 100644
index 0000000000..ab33560b35
--- /dev/null
+++ b/dom/events/test/pointerevents/wpt/resources/pointerevent_pointerId_scope-iframe.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html>
+ <!--
+Test cases for Pointer Events v1 spec
+This document references Test Assertions (abbrev TA below) written by Cathy Chan
+http://www.w3.org/wiki/PointerEvents/TestAssertions
+-->
+ <head>
+ <title>Pointer Events pointerdown tests</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+ <script>
+ function run() {
+ var target1 = document.getElementById("target1");
+
+ var eventList = ['pointerenter', 'pointerover', 'pointermove', 'pointerout', 'pointerleave'];
+
+ eventList.forEach(function(eventName) {
+ target1.addEventListener(eventName, function (event) {
+ var pass_data = {
+ 'pointerId' : event.pointerId,
+ 'type' : event.type,
+ 'pointerType' : event.pointerType
+ };
+ top.postMessage(JSON.stringify(pass_data), "*");
+ });
+ });
+ }
+ </script>
+ </head>
+ <body onload="run()">
+ <div id="target1" class="touchActionNone">
+ </div>
+ </body>
+</html>
diff --git a/dom/events/test/test_DataTransferItemList.html b/dom/events/test/test_DataTransferItemList.html
new file mode 100644
index 0000000000..980d0d183f
--- /dev/null
+++ b/dom/events/test/test_DataTransferItemList.html
@@ -0,0 +1,234 @@
+<html>
+<head>
+ <title>Tests for the DataTransferItemList object</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body style="height: 300px; overflow: auto;">
+<p id="display"> </p>
+<img id="image" draggable="true" src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82">
+<div id="over" style="width: 100px; height: 100px; border: 2px black dashed;">
+ drag over here
+</div>
+
+<script>
+ function spin() {
+ // Defer to the event loop twice to wait for any events to be flushed out.
+ return new Promise(function(a) {
+ SimpleTest.executeSoon(function() {
+ SimpleTest.executeSoon(a)
+ });
+ });
+ }
+
+ add_task(async function() {
+ await spin();
+ var draggable = document.getElementById('image');
+ var over = document.getElementById('over');
+
+ var dragstartFired = 0;
+ draggable.addEventListener('dragstart', onDragStart);
+ function onDragStart(e) {
+ draggable.removeEventListener('dragstart', onDragStart);
+
+ var dt = e.dataTransfer;
+ dragstartFired++;
+
+ ok(true, "dragStart event fired");
+ var dtList = e.dataTransfer.items;
+ ok(dtList instanceof DataTransferItemList,
+ "DataTransfer.items returns a DataTransferItemList");
+
+ for (var i = 0; i < dtList.length; i++) {
+ var item = dtList[i];
+ ok(item instanceof DataTransferItem,
+ "operator[] returns DataTransferItem objects");
+ if (item.kind == "file") {
+ var file = item.getAsFile();
+ ok(file instanceof File, "getAsFile() returns File objects");
+ }
+ }
+
+ dtList.clear();
+ is(dtList.length, 0, "after .clear() DataTransferItemList should be empty");
+
+ dtList.add("this is some text", "text/plain");
+ dtList.add("<a href='www.mozilla.org'>this is a link</a>", "text/html");
+ dtList.add("http://www.mozilla.org", "text/uri-list");
+ dtList.add("this is custom-data", "custom-data");
+
+
+ var file = new File(['<a id="a"><b id="b">hey!</b></a>'], "myfile.html",
+ {type: "text/html"});
+
+ dtList.add(file);
+
+ checkTypes(["text/plain", "text/html", "text/uri-list", "custom-data", "text/html"],
+ dtList, "DataTransferItemList.add test");
+
+ var files = e.dataTransfer.files;
+ is(files.length, 1, "DataTransfer.files should contain the one file we added earlier");
+ is(files[0], file, "It should be the same file as the file we originally created");
+ is(file, e.dataTransfer.mozGetDataAt("text/html", 1),
+ "It should be stored in index 1 for mozGetDataAt");
+
+ var file2 = new File(['<a id="c"><b id="d">yo!</b></a>'], "myotherfile.html",
+ {type: "text/html"});
+ dtList.add(file2);
+
+ todo(files.length == 2, "This test has chrome privileges, so the FileList objects aren't updated live");
+ files = e.dataTransfer.files;
+ is(files.length, 2, "The files property should have been updated in place");
+ is(files[1], file2, "It should be the same file as the file we originally created");
+ is(file2, e.dataTransfer.mozGetDataAt("text/html", 2),
+ "It should be stored in index 2 for mozGetDataAt");
+
+ var oldLength = dtList.length;
+ var randomString = "foo!";
+ e.dataTransfer.mozSetDataAt("random/string", randomString, 3);
+ is(oldLength, dtList.length,
+ "Adding a non-file entry to a non-zero index should not add an item to the items list");
+
+ var file3 = new File(['<a id="e"><b id="f">heya!</b></a>'], "yetanotherfile.html",
+ {type: "text/html"});
+ e.dataTransfer.mozSetDataAt("random/string", file3, 3);
+ is(oldLength + 1, dtList.length,
+ "Replacing the entry with a file should add it to the list!");
+ is(dtList[oldLength].getAsFile(), file3, "It should be stored in the last index as a file");
+ is(dtList[oldLength].type, "text/html", "It should have the correct type");
+ is(dtList[oldLength].kind, "file", "It should have the correct kind");
+
+ todo(files.length == 3, "This test has chrome privileges, so the FileList objects aren't updated live");
+ files = e.dataTransfer.files;
+ is(files[files.length - 1], file3, "It should also be in the files list");
+
+ oldLength = dtList.length;
+ var nonstring = {};
+ e.dataTransfer.mozSetDataAt("jsobject", nonstring, 0);
+ is(oldLength + 1, dtList.length,
+ "Adding a non-string object using the mozAPIs to index 0 should add an item to the dataTransfer");
+ is(dtList[oldLength].type, "jsobject", "It should have the correct type");
+ is(dtList[oldLength].kind, "other", "It should have the correct kind");
+
+ // Clear the event's data and get it set up so we can read it later!
+ dtList.clear();
+
+ dtList.add(file);
+ dtList.add("this is some text", "text/plain");
+ is(e.dataTransfer.mozGetDataAt("text/html", 1), file);
+ }
+
+ var getAsStringCalled = 0;
+ var dragenterFired = 0;
+ over.addEventListener('dragenter', onDragEnter);
+ function onDragEnter(e) {
+ over.removeEventListener('dragenter', onDragEnter);
+
+ var dt = e.dataTransfer;
+ dragenterFired++;
+
+ // NOTE: This test is run with chrome privileges.
+ // For back-compat reasons, protected mode acts like readonly mode for
+ // chrome documents.
+ readOnly(e);
+ }
+
+ var dropFired = 0;
+ over.addEventListener('drop', onDrop);
+ function onDrop(e) {
+ over.removeEventListener('drop', onDrop);
+
+ var dt = e.dataTransfer;
+ dropFired++;
+ e.preventDefault();
+
+ readOnly(e);
+ }
+
+
+ function readOnly(e) {
+ var dtList = e.dataTransfer.items;
+ var num = dtList.length;
+
+ // .clear() should have no effect
+ dtList.clear();
+ is(dtList.length, num,
+ ".clear() should have no effect on the object during a readOnly event");
+
+ // .remove(i) should throw InvalidStateError
+ for (var i = 0; i < dtList.length; i++) {
+ expectError(function() { dtList.remove(i); },
+ "InvalidStateError", ".remove(" + i + ") during a readOnly event");
+ }
+
+ // .add() should return null and have no effect
+ var data = [["This is a plain string", "text/plain"],
+ ["This is <em>HTML!</em>", "text/html"],
+ ["http://www.mozilla.org/", "text/uri-list"],
+ ["this is some custom data", "custom-data"]];
+
+ for (var i = 0; i < data.length; i++) {
+ is(dtList.add(data[i][0], data[i][1]), null,
+ ".add() should return null during a readOnly event");
+
+ is(dtList.length, num, ".add() should have no effect during a readOnly event");
+ }
+
+ // .add() with a file should return null and have no effect
+ var file = new File(['<a id="a"><b id="b">hey!</b></a>'], "myfile.html",
+ {type: "text/html"});
+ is(dtList.add(file), null, ".add() with a file should return null during a readOnly event");
+ is(dtList.length, num, ".add() should have no effect during a readOnly event");
+
+ // We should be able to access the files
+ is(e.dataTransfer.files.length, 1, "Should be able to access files");
+ ok(e.dataTransfer.files[0], "File should be the same file!");
+ is(e.dataTransfer.items.length, 2, "Should be able to see there are 2 items");
+
+ is(e.dataTransfer.items[0].kind, "file", "First item should be a file");
+ is(e.dataTransfer.items[1].kind, "string", "Second item should be a string");
+
+ is(e.dataTransfer.items[0].type, "text/html", "first item should be text/html");
+ is(e.dataTransfer.items[1].type, "text/plain", "second item should be text/plain");
+
+ ok(e.dataTransfer.items[0].getAsFile(), "Should be able to get file");
+ e.dataTransfer.items[1].getAsString(function(s) {
+ getAsStringCalled++;
+ is(s, "this is some text", "Should provide the correct string");
+ });
+ }
+
+ synthesizeDrop(draggable, over, null, null);
+
+ // Wait for the getAsString callbacks to complete
+ await spin();
+ is(getAsStringCalled, 2, "getAsString should be called twice");
+
+ // Sanity-check to make sure that the events were actually run
+ is(dragstartFired, 1, "dragstart fired");
+ is(dragenterFired, 1, "dragenter fired");
+ is(dropFired, 1, "drop fired");
+ });
+
+ function expectError(fn, eid, testid) {
+ var error = "";
+ try {
+ fn();
+ } catch (ex) {
+ error = ex.name;
+ }
+ is(error, eid, testid + " causes exception " + eid);
+ }
+
+ function checkTypes(aExpectedList, aDtList, aTestid) {
+ is(aDtList.length, aExpectedList.length, aTestid + " length test");
+ for (var i = 0; i < aExpectedList.length; i++) {
+ is(aDtList[i].type, aExpectedList[i], aTestid + " type " + i);
+ }
+ }
+</script>
+
+</body>
+</html>
diff --git a/dom/events/test/test_accel_virtual_modifier.html b/dom/events/test/test_accel_virtual_modifier.html
new file mode 100644
index 0000000000..6d98053fa2
--- /dev/null
+++ b/dom/events/test/test_accel_virtual_modifier.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for DOM "Accel" virtual modifier</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+var kAccel = "Accel";
+var kAccelKeyCode = SpecialPowers.getIntPref("ui.key.accelKey");
+
+var mouseEvent = new MouseEvent("mousedown", {});
+is(mouseEvent.getModifierState(kAccel), false,
+ "MouseEvent.getModifierState(\"" + kAccel + "\") should be false");
+mouseEvent = new MouseEvent("wheel", { accelKey: true});
+is(mouseEvent.getModifierState(kAccel), false,
+ "MouseEvent.getModifierState(\"" + kAccel + "\") should be false due to not supporting accelKey attribute");
+mouseEvent = new MouseEvent("mousedown", { ctrlKey: true });
+is(mouseEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_CONTROL,
+ "MouseEvent.getModifierState(\"" + kAccel + "\") should be true if ctrlKey is an accel modifier");
+mouseEvent = new MouseEvent("mousedown", { altKey: true });
+is(mouseEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_ALT,
+ "MouseEvent.getModifierState(\"" + kAccel + "\") should be true if altKey is an accel modifier");
+mouseEvent = new MouseEvent("mousedown", { metaKey: true });
+is(mouseEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_META,
+ "MouseEvent.getModifierState(\"" + kAccel + "\") should be true if metaKey is an accel modifier");
+mouseEvent = new MouseEvent("mousedown", { ctrlKey: true, altKey: true, metaKey: true });
+is(mouseEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_CONTROL ||
+ kAccelKeyCode == KeyboardEvent.DOM_VK_ALT ||
+ kAccelKeyCode == KeyboardEvent.DOM_VK_META,
+ "MouseEvent.getModifierState(\"" + kAccel + "\") should be true if one of ctrlKey, altKey or metaKey is an accel modifier");
+
+var wheelEvent = new WheelEvent("wheel", {});
+is(wheelEvent.getModifierState(kAccel), false,
+ "WheelEvent.getModifierState(\"" + kAccel + "\") should be false");
+wheelEvent = new WheelEvent("wheel", { accelKey: true});
+is(wheelEvent.getModifierState(kAccel), false,
+ "WheelEvent.getModifierState(\"" + kAccel + "\") should be false due to not supporting accelKey attribute");
+wheelEvent = new WheelEvent("wheel", { ctrlKey: true });
+is(wheelEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_CONTROL,
+ "WheelEvent.getModifierState(\"" + kAccel + "\") should be true if ctrlKey is an accel modifier");
+wheelEvent = new WheelEvent("wheel", { altKey: true });
+is(wheelEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_ALT,
+ "WheelEvent.getModifierState(\"" + kAccel + "\") should be true if altKey is an accel modifier");
+wheelEvent = new WheelEvent("wheel", { metaKey: true });
+is(wheelEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_META,
+ "WheelEvent.getModifierState(\"" + kAccel + "\") should be true if metaKey is an accel modifier");
+wheelEvent = new WheelEvent("wheel", { ctrlKey: true, altKey: true, metaKey: true });
+is(wheelEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_CONTROL ||
+ kAccelKeyCode == KeyboardEvent.DOM_VK_ALT ||
+ kAccelKeyCode == KeyboardEvent.DOM_VK_META,
+ "WheelEvent.getModifierState(\"" + kAccel + "\") should be true if one of ctrlKey, altKey or metaKey is an accel modifier");
+
+var keyboardEvent = new KeyboardEvent("keydown", {});
+is(keyboardEvent.getModifierState(kAccel), false,
+ "KeyboardEvent.getModifierState(\"" + kAccel + "\") should be false");
+keyboardEvent = new KeyboardEvent("keydown", { accelKey: true});
+is(keyboardEvent.getModifierState(kAccel), false,
+ "KeyboardEvent.getModifierState(\"" + kAccel + "\") should be false due to not supporting accelKey attribute");
+keyboardEvent = new KeyboardEvent("keydown", { ctrlKey: true });
+is(keyboardEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_CONTROL,
+ "KeyboardEvent.getModifierState(\"" + kAccel + "\") should be true if ctrlKey is an accel modifier");
+keyboardEvent = new KeyboardEvent("keydown", { altKey: true });
+is(keyboardEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_ALT,
+ "KeyboardEvent.getModifierState(\"" + kAccel + "\") should be true if altKey is an accel modifier");
+keyboardEvent = new KeyboardEvent("keydown", { metaKey: true });
+is(keyboardEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_META,
+ "KeyboardEvent.getModifierState(\"" + kAccel + "\") should be true if metaKey is an accel modifier");
+keyboardEvent = new KeyboardEvent("keydown", { ctrlKey: true, altKey: true, metaKey: true });
+is(keyboardEvent.getModifierState(kAccel), kAccelKeyCode == KeyboardEvent.DOM_VK_CONTROL ||
+ kAccelKeyCode == KeyboardEvent.DOM_VK_ALT ||
+ kAccelKeyCode == KeyboardEvent.DOM_VK_META,
+ "KeyboardEvent.getModifierState(\"" + kAccel + "\") should be true if one of ctrlKey, altKey or metaKey is an accel modifier");
+
+// "Accel" virtual modifier must be supported with getModifierState(). So, any legacy init*Event()'s
+// modifiers list argument shouldn't accept "Accel".
+ok(typeof(KeyboardEvent.initKeyboardEvent) != "function",
+ "If we would support KeyboardEvent.initKeyboardEvent, we should test its modifier list argument doesn't accept \"" + kAccel + "\"");
+
+</script>
+</pre>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=828554
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 828554</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 828554 **/
+ SimpleTest.waitForExplicitFinish();
+ window.addEventListener("message", function() {
+ ok(true, "We got called");
+ SimpleTest.finish();
+ }, false, undefined);
+ window.postMessage("Hey there", "*");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=828554">Mozilla Bug 828554</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
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..847dc1398b
--- /dev/null
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -0,0 +1,470 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test all synthetic events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/**
+ * kEventConstructors is a helper and database of all events.
+ * The sort order of the definition is by A to Z (ignore the Event postfix).
+ *
+ * XXX: should we move this into EventUtils.js?
+ *
+ * create: function or null. If this is null, it's impossible to create untrusted event for it.
+ * Otherwise, create(aName, aProps) returns an instance of the event initialized with aProps.
+ * aName specifies the event's type name. See each create() code for the detail of aProps.
+ */
+const kEventConstructors = {
+ Event: { create (aName, aProps) {
+ return new Event(aName, aProps);
+ },
+ },
+ AnimationEvent: { create (aName, aProps) {
+ return new AnimationEvent(aName, aProps);
+ },
+ },
+ AnimationPlaybackEvent: { create (aName, aProps) {
+ return new AnimationPlaybackEvent(aName, aProps);
+ },
+ },
+ AudioProcessingEvent: { create: null, // Cannot create untrusted event from JS.
+ },
+ BeforeUnloadEvent: { create (aName, aProps) {
+ var e = document.createEvent("beforeunloadevent");
+ e.initEvent(aName, aProps.bubbles, aProps.cancelable);
+ return e;
+ },
+ },
+ BlobEvent: { create (aName, aProps) {
+ return new BlobEvent(aName, {
+ data: new Blob([]),
+ });
+ },
+ },
+ CallEvent: { create (aName, aProps) {
+ return new CallEvent(aName, aProps);
+ },
+ },
+ CallGroupErrorEvent: { create (aName, aProps) {
+ return new CallGroupErrorEvent(aName, aProps);
+ },
+ },
+ CFStateChangeEvent: { create (aName, aProps) {
+ return new CFStateChangeEvent(aName, aProps);
+ },
+ },
+ CloseEvent: { create (aName, aProps) {
+ return new CloseEvent(aName, aProps);
+ },
+ },
+ ClipboardEvent: { create (aName, aProps) {
+ return new ClipboardEvent(aName, aProps);
+ },
+ },
+ CompositionEvent: { create (aName, aProps) {
+ var e = document.createEvent("compositionevent");
+ e.initCompositionEvent(aName, aProps.bubbles, aProps.cancelable,
+ aProps.view, aProps.data, aProps.locale);
+ return e;
+ },
+ },
+ CustomEvent: { create (aName, aProps) {
+ return new CustomEvent(aName, aProps);
+ },
+ },
+ DataErrorEvent: { create (aName, aProps) {
+ return new DataErrorEvent(aName, aProps);
+ },
+ },
+ DeviceLightEvent: { create (aName, aProps) {
+ return new DeviceLightEvent(aName, aProps);
+ },
+ },
+ DeviceMotionEvent: { create (aName, aProps) {
+ var e = document.createEvent("devicemotionevent");
+ e.initDeviceMotionEvent(aName, aProps.bubbles, aProps.cancelable, aProps.acceleration,
+ aProps.accelerationIncludingGravity, aProps.rotationRate,
+ aProps.interval || 0.0);
+ return e;
+ },
+ },
+ DeviceOrientationEvent: { create (aName, aProps) {
+ return new DeviceOrientationEvent(aName, aProps);
+ },
+ },
+ DeviceProximityEvent: { create (aName, aProps) {
+ return new DeviceProximityEvent(aName, aProps);
+ },
+ },
+ DownloadEvent: { create (aName, aProps) {
+ return new DownloadEvent(aName, aProps);
+ },
+ },
+ DragEvent: { create (aName, aProps) {
+ var e = document.createEvent("dragevent");
+ e.initDragEvent(aName, aProps.bubbles, aProps.cancelable,
+ aProps.view, aProps.detail,
+ aProps.screenX, aProps.screenY,
+ aProps.clientX, aProps.clientY,
+ aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey,
+ aProps.button, aProps.relatedTarget, aProps.dataTransfer);
+ return e;
+ },
+ },
+ ErrorEvent: { create (aName, aProps) {
+ return new ErrorEvent(aName, aProps);
+ },
+ },
+ FocusEvent: { create (aName, aProps) {
+ return new FocusEvent(aName, aProps);
+ },
+ },
+ FontFaceSetLoadEvent: { create (aName, aProps) {
+ return new FontFaceSetLoadEvent(aName, aProps);
+ },
+ },
+ FormDataEvent: { create (aName, aProps) {
+ return new FormDataEvent(aName, {
+ formData: new FormData()
+ });
+ },
+ },
+ GamepadEvent: { create (aName, aProps) {
+ return new GamepadEvent(aName, aProps);
+ },
+ },
+ GamepadAxisMoveEvent: { create (aName, aProps) {
+ return new GamepadAxisMoveEvent(aName, aProps);
+ },
+ },
+ GamepadButtonEvent: { create (aName, aProps) {
+ return new GamepadButtonEvent(aName, aProps);
+ },
+ },
+ GPUUncapturedErrorEvent: { create: null, //TODO: constructor test
+ },
+ HashChangeEvent: { create (aName, aProps) {
+ return new HashChangeEvent(aName, aProps);
+ },
+ },
+ IDBVersionChangeEvent: { create (aName, aProps) {
+ return new IDBVersionChangeEvent(aName, aProps);
+ },
+ },
+ ImageCaptureErrorEvent: { create (aName, aProps) {
+ return new ImageCaptureErrorEvent(aName, aProps);
+ },
+ },
+ InputEvent: { create (aName, aProps) {
+ return new InputEvent(aName, aProps);
+ },
+ },
+ KeyEvent: { create (aName, aProps) {
+ return new KeyboardEvent(aName, aProps);
+ },
+ },
+ KeyboardEvent: { create (aName, aProps) {
+ return new KeyboardEvent(aName, aProps);
+ },
+ },
+ MediaEncryptedEvent: { create (aName, aProps) {
+ return new MediaEncryptedEvent(aName, aProps);
+ },
+ },
+ MediaKeyMessageEvent: { create (aName, aProps) {
+ return new MediaKeyMessageEvent(aName, {
+ messageType: "license-request",
+ message: new ArrayBuffer(0)
+ });
+ },
+ },
+ MediaQueryListEvent: { create (aName, aProps) {
+ return new MediaQueryListEvent(aName, aProps);
+ },
+ },
+ MediaRecorderErrorEvent: { create (aName, aProps) {
+ aProps.error = new DOMException();
+ return new MediaRecorderErrorEvent(aName, aProps);
+ },
+ },
+ MediaStreamEvent: { create (aName, aProps) {
+ return new MediaStreamEvent(aName, aProps);
+ },
+ },
+ MediaStreamTrackEvent: {
+ // Difficult to test required arguments.
+ },
+ MessageEvent: { create (aName, aProps) {
+ var e = new MessageEvent("messageevent", { bubbles: aProps.bubbles,
+ cancelable: aProps.cancelable, data: aProps.data, origin: aProps.origin,
+ lastEventId: aProps.lastEventId, source: aProps.source });
+ return e;
+ },
+ },
+ MouseEvent: { create (aName, aProps) {
+ return new MouseEvent(aName, aProps);
+ },
+ },
+ MouseScrollEvent: { create: null
+ // Cannot create untrusted event from JS
+ },
+ MozApplicationEvent: { create (aName, aProps) {
+ return new MozApplicationEvent(aName, aProps);
+ },
+ },
+ MozClirModeEvent: { create (aName, aProps) {
+ return new MozClirModeEvent(aName, aProps);
+ },
+ },
+ MozContactChangeEvent: { create (aName, aProps) {
+ return new MozContactChangeEvent(aName, aProps);
+ },
+ },
+ MozEmergencyCbModeEvent: { create (aName, aProps) {
+ return new MozEmergencyCbModeEvent(aName, aProps);
+ },
+ },
+ MozMessageDeletedEvent: { create (aName, aProps) {
+ return new MozMessageDeletedEvent(aName, aProps);
+ },
+ },
+ MozMmsEvent: { create (aName, aProps) {
+ return new MozMmsEvent(aName, aProps);
+ },
+ },
+ MozOtaStatusEvent: { create (aName, aProps) {
+ return new MozOtaStatusEvent(aName, aProps);
+ },
+ },
+ MozSmsEvent: { create (aName, aProps) {
+ return new MozSmsEvent(aName, aProps);
+ },
+ },
+ MozStkCommandEvent: { create (aName, aProps) {
+ return new MozStkCommandEvent(aName, aProps);
+ },
+ },
+ MutationEvent: { create (aName, aProps) {
+ var e = document.createEvent("mutationevent");
+ e.initMutationEvent(aName, aProps.bubbles, aProps.cancelable,
+ aProps.relatedNode, aProps.prevValue, aProps.newValue,
+ aProps.attrName, aProps.attrChange);
+ return e;
+ },
+ },
+ OfflineAudioCompletionEvent: { create: "AudioContext" in self
+ ? function (aName, aProps) {
+ var ac = new AudioContext();
+ var ab = new AudioBuffer({ length: 42, sampleRate: ac.sampleRate });
+ aProps.renderedBuffer = ab;
+ return new OfflineAudioCompletionEvent(aName, aProps);
+ }
+ : null,
+ },
+ PageTransitionEvent: { create (aName, aProps) {
+ return new PageTransitionEvent(aName, aProps);
+ },
+ },
+ PointerEvent: { create (aName, aProps) {
+ return new PointerEvent(aName, aProps);
+ },
+ },
+ PopStateEvent: { create (aName, aProps) {
+ return new PopStateEvent(aName, aProps);
+ },
+ },
+ PopupBlockedEvent: { create (aName, aProps) {
+ return new PopupBlockedEvent(aName, aProps);
+ },
+ },
+ ProgressEvent: { create (aName, aProps) {
+ return new ProgressEvent(aName, aProps);
+ },
+ },
+ PromiseRejectionEvent: { create (aName, aProps) {
+ aProps.promise = new Promise(() => {});
+ return new PromiseRejectionEvent(aName, aProps);
+ },
+ },
+ RTCDataChannelEvent: { create (aName, aProps) {
+ let pc = new RTCPeerConnection();
+ aProps.channel = pc.createDataChannel("foo");
+ let e = new RTCDataChannelEvent(aName, aProps);
+ aProps.channel.close();
+ pc.close();
+ return e;
+ },
+ },
+ RTCDTMFToneChangeEvent: { create (aName, aProps) {
+ return new RTCDTMFToneChangeEvent(aName, aProps);
+ },
+ },
+ RTCPeerConnectionIceEvent: { create (aName, aProps) {
+ return new RTCPeerConnectionIceEvent(aName, aProps);
+ },
+ },
+ RTCTrackEvent: {
+ // Difficult to test required arguments.
+ },
+ ScrollAreaEvent: { create: null
+ // Cannot create untrusted event from JS
+ },
+ SpeechRecognitionError: { create (aName, aProps) {
+ return new SpeechRecognitionError(aName, aProps);
+ },
+ },
+ SpeechRecognitionEvent: { create (aName, aProps) {
+ return new SpeechRecognitionEvent(aName, aProps);
+ },
+ },
+ SpeechSynthesisErrorEvent: { create (aName, aProps) {
+ aProps.error = "synthesis-unavailable";
+ aProps.utterance = new SpeechSynthesisUtterance("Hello World");
+ return new SpeechSynthesisErrorEvent(aName, aProps);
+ },
+ },
+ SpeechSynthesisEvent: { create (aName, aProps) {
+ aProps.utterance = new SpeechSynthesisUtterance("Hello World");
+ return new SpeechSynthesisEvent(aName, aProps);
+ },
+ },
+ StorageEvent: { create (aName, aProps) {
+ return new StorageEvent(aName, aProps);
+ },
+ },
+ StyleSheetApplicableStateChangeEvent: { create (aName, aProps) {
+ return new StyleSheetApplicableStateChangeEvent(aName, aProps);
+ },
+ chromeOnly: true,
+ },
+ SubmitEvent: { create (aName, aProps) {
+ return new SubmitEvent(aName, aProps);
+ },
+ },
+ TCPSocketErrorEvent: { create(aName, aProps) {
+ return new TCPSocketErrorEvent(aName, aProps);
+ },
+ },
+ TCPSocketEvent: { create(aName, aProps) {
+ return new TCPSocketEvent(aName, aProps);
+ },
+ },
+ TCPServerSocketEvent: { create(aName, aProps) {
+ return new TCPServerSocketEvent(aName, aProps);
+ },
+ },
+ TimeEvent: { create: null
+ // Cannot create untrusted event from JS
+ },
+ TouchEvent: { create (aName, aProps) {
+ var e = document.createEvent("touchevent");
+ e.initTouchEvent(aName, aProps.bubbles, aProps.cancelable,
+ aProps.view, aProps.detail,
+ aProps.ctrlKey, aProps.altKey, aProps.shiftKey, aProps.metaKey,
+ aProps.touches, aProps.targetTouches, aProps.changedTouches);
+ return e;
+ },
+ },
+ TrackEvent: { create (aName, aProps) {
+ return new TrackEvent(aName, aProps);
+ },
+ },
+ TransitionEvent: { create (aName, aProps) {
+ return new TransitionEvent(aName, aProps);
+ },
+ },
+ UIEvent: { create (aName, aProps) {
+ return new UIEvent(aName, aProps);
+ },
+ },
+ UserProximityEvent: { create (aName, aProps) {
+ return new UserProximityEvent(aName, aProps);
+ },
+ },
+ USSDReceivedEvent: { create (aName, aProps) {
+ return new USSDReceivedEvent(aName, aProps);
+ },
+ },
+ VRDisplayEvent: { create: null,
+ // Required argument expects a VRDisplay that can not
+ // be created from Javascript without physical VR hardware
+ // connected. When Bug 1229480 lands, this test can be
+ // updated to use the puppet VR device.
+ },
+ WheelEvent: { create (aName, aProps) {
+ return new WheelEvent(aName, aProps);
+ },
+ },
+ WebGLContextEvent: { create (aName, aProps) {
+ return new WebGLContextEvent(aName, aProps);
+ },
+ },
+ SecurityPolicyViolationEvent: { create (aName, aProps) {
+ return new SecurityPolicyViolationEvent(aName, aProps);
+ },
+ },
+};
+
+function test() {
+ for (var name of Object.keys(kEventConstructors)) {
+ if (!kEventConstructors[name].chromeOnly) {
+ continue;
+ }
+ if (window[name]) {
+ ok(false, name + " should be chrome only.");
+ }
+ window[name] = SpecialPowers.unwrap(SpecialPowers.wrap(window)[name]);
+ }
+
+ var props = Object.getOwnPropertyNames(window);
+ for (var i = 0; i < props.length; i++) {
+ // Assume that event object must be named as "FooBarEvent".
+ if (!props[i].match(/^([A-Z][a-zA-Z]+)?Event$/)) {
+ continue;
+ }
+ if (!kEventConstructors[props[i]]) {
+ ok(false, "Unknown event found: " + props[i]);
+ continue;
+ }
+ if (!kEventConstructors[props[i]].create) {
+ todo(false, "Cannot create untrusted event of " + props[i]);
+ continue;
+ }
+ ok(true, "Creating " + props[i] + "...");
+ var event = kEventConstructors[props[i]].create("foo", {});
+ if (!event) {
+ ok(false, "Failed to create untrusted event: " + props[i]);
+ continue;
+ }
+ if (typeof(event.getModifierState) == "function") {
+ const kModifiers = [ "Shift", "Control", "Alt", "AltGr", "Meta", "CapsLock", "ScrollLock", "NumLock", "OS", "Fn", "FnLock", "Symbol", "SymbolLock" ];
+ for (var j = 0; j < kModifiers.length; j++) {
+ ok(true, "Calling " + props[i] + ".getModifierState(" + kModifiers[j] + ")...");
+ var modifierState = event.getModifierState(kModifiers[j]);
+ ok(true, props[i] + ".getModifierState(" + kModifiers[j] + ") = " + modifierState);
+ }
+ }
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+ {"set": [["dom.w3c_touch_events.legacy_apis.enabled", true],
+ ["dom.formdata.event.enabled", true]]},
+ function() {
+ test();
+ SimpleTest.finish();
+ });
+</script>
+</pre>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1003432
+-->
+<head>
+ <title>Test for Bug 1003432</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1003432">Mozilla Bug 1003432</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1003432 **/
+// Test CustomEvent on worker
+SimpleTest.waitForExplicitFinish();
+var worker = new Worker("test_bug1003432.js");
+ok(worker, "Should have worker!");
+
+var count = 0;
+worker.onmessage = function(evt) {
+ is(evt.data.type, "foobar", "Should get 'foobar' event!");
+ is(evt.data.detail, "test", "Detail should be 'test'.");
+ ok(evt.data.bubbles, "Event should bubble!");
+ ok(evt.data.cancelable, "Event should be cancelable.");
+
+ // wait for test results of constructor and initCustomEvent
+ if (++count == 2) {
+ worker.terminate();
+ SimpleTest.finish();
+ }
+};
+
+worker.postMessage("");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1003432.js b/dom/events/test/test_bug1003432.js
new file mode 100644
index 0000000000..93d408663f
--- /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..938445bd66
--- /dev/null
+++ b/dom/events/test/test_bug1013412.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1013412
+-->
+<head>
+ <title>Test for Bug 1013412</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ #content {
+ height: 800px;
+ overflow: scroll;
+ }
+
+ #scroller {
+ height: 2000px;
+ background: repeating-linear-gradient(#EEE, #EEE 100px, #DDD 100px, #DDD 200px);
+ }
+
+ #scrollbox {
+ margin-top: 200px;
+ width: 500px;
+ height: 500px;
+ border-radius: 250px;
+ box-shadow: inset 0 0 0 60px #555;
+ background: #777;
+ }
+
+ #circle {
+ position: relative;
+ left: 240px;
+ top: 20px;
+ border: 10px solid white;
+ border-radius: 10px;
+ width: 0px;
+ height: 0px;
+ transform-origin: 10px 230px;
+ will-change: transform;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1013412">Mozilla Bug 1013412</a>
+<p id="display"></p>
+<div id="content">
+ <p>Scrolling the page should be async, but scrolling over the dark circle should not scroll the page and instead rotate the white ball.</p>
+ <div id="scroller">
+ <div id="scrollbox">
+ <div id="circle"></div>
+ </div>
+ </div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1013412 **/
+
+var rotation = 0;
+var rotationAdjusted = false;
+
+var incrementForMode = function (mode) {
+ switch (mode) {
+ case WheelEvent.DOM_DELTA_PIXEL: return 1;
+ case WheelEvent.DOM_DELTA_LINE: return 15;
+ case WheelEvent.DOM_DELTA_PAGE: return 400;
+ }
+ return 0;
+};
+
+document.getElementById("scrollbox").addEventListener("wheel", function (e) {
+ rotation += e.deltaY * incrementForMode(e.deltaMode) * 0.2;
+ document.getElementById("circle").style.transform = "rotate(" + rotation + "deg)";
+ rotationAdjusted = true;
+ e.preventDefault();
+});
+
+var iteration = 0;
+function runTest() {
+ var content = document.getElementById('content');
+ if (iteration < 300) { // enough iterations that we would scroll to the bottom of 'content'
+ iteration++;
+ sendWheelAndPaint(content, 100, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 },
+ runTest);
+ return;
+ }
+ var scrollbox = document.getElementById('scrollbox');
+ is(content.scrollTop < content.scrollTopMax, true, "We should not have scrolled to the bottom of the scrollframe");
+ is(rotationAdjusted, true, "The rotation should have been adjusted");
+ SimpleTest.finish();
+}
+
+function startTest() {
+ // If we allow smooth scrolling the "smooth" scrolling may cause the page to
+ // glide past the scrollbox (which is supposed to stop the scrolling) and so
+ // we might end up at the bottom of the page.
+ SpecialPowers.pushPrefEnv({"set": [["general.smoothScroll", false]]}, runTest);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(startTest, window);
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug1017086_disable.html b/dom/events/test/test_bug1017086_disable.html
new file mode 100644
index 0000000000..e8281cac35
--- /dev/null
+++ b/dom/events/test/test_bug1017086_disable.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1017086
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1017086</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ /** Test for Bug 1017086 **/
+ var pointer_events_enabled = false;
+ function prepareTest() {
+ SimpleTest.waitForExplicitFinish();
+ turnOnOffPointerEvents(startTest);
+ }
+ function turnOnOffPointerEvents(callback) {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.w3c_pointer_events.enabled", pointer_events_enabled]
+ ]
+ }, callback);
+ }
+ function startTest() {
+ var iframe = document.getElementById("testFrame");
+ iframe.src = "bug1017086_inner.html";
+ }
+ function part_of_checks(pointer_events, check, window, document, testelem) {
+ for(item in pointer_events) { check(false, pointer_events[item], window, "window"); }
+ for(item in pointer_events) { check(false, pointer_events[item], document, "document"); }
+ for(item in pointer_events) { check(false, pointer_events[item], testelem, "element"); }
+ SimpleTest.finish();
+ }
+ </script>
+ </head>
+ <body onload="prepareTest()">
+ <iframe id="testFrame" height="700" width="700"></iframe>
+ </body>
+</html>
diff --git a/dom/events/test/test_bug1017086_enable.html b/dom/events/test/test_bug1017086_enable.html
new file mode 100644
index 0000000000..df6572b86c
--- /dev/null
+++ b/dom/events/test/test_bug1017086_enable.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1017086
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1017086</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ /** Test for Bug 1017086 **/
+ var pointer_events_enabled = true;
+ function prepareTest() {
+ SimpleTest.waitForExplicitFinish();
+ turnOnOffPointerEvents(startTest);
+ }
+ function turnOnOffPointerEvents(callback) {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.w3c_pointer_events.enabled", pointer_events_enabled]
+ ]
+ }, callback);
+ }
+ function startTest() {
+ var iframe = document.getElementById("testFrame");
+ iframe.src = "bug1017086_inner.html";
+ }
+ function part_of_checks(pointer_events, check, window, document, testelem) {
+ for(item in pointer_events) { check(true, pointer_events[item], window, "window"); }
+ /** TODO
+ for(item in pointer_events) { check(false, pointer_events[item], document, "document"); }
+ **/
+ for(item in pointer_events) { check(true, pointer_events[item], testelem, "element"); }
+ SimpleTest.finish();
+ }
+ </script>
+ </head>
+ <body onload="prepareTest()">
+ <iframe id="testFrame" height="700" width="700"></iframe>
+ </body>
+</html>
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 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1037990
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1037990</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1037990">Mozilla Bug 1037990</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<script type="application/javascript">
+
+ /** Test for Bug 1037990 **/
+
+ var pre, node, detachedAccess, attachedAcess;
+
+ node = document.createElement('a');
+ node.href = 'http://example.org';
+ node.accessKey = 'e';
+ detachedAccess = node.accessKeyLabel;
+ info('[window.document] detached: ' + detachedAccess);
+ document.body.appendChild(node);
+ attachedAcess = node.accessKeyLabel;
+ info('[window.document] attached: ' + attachedAcess);
+ is(detachedAccess, attachedAcess, "Both values are same for the window.document");
+
+ var parser=new DOMParser();
+ var xmlDoc=parser.parseFromString("<root></root>","text/xml");
+ var nn = xmlDoc.createElementNS('http://www.w3.org/1999/xhtml','a');
+ nn.setAttribute('accesskey','t')
+ detachedAccess = nn.accessKeyLabel;
+ info('[xmlDoc] detached: ' + detachedAccess);
+ var root = xmlDoc.getElementsByTagName('root')[0];
+ root.appendChild(nn);
+ attachedAcess = nn.accessKeyLabel;
+ info('[xmlDoc] attached: ' + attachedAcess);
+ is(detachedAccess, attachedAcess, "Both values are same for the xmlDoc");
+
+ var myDoc = new Document();
+ var newnode = myDoc.createElementNS('http://www.w3.org/1999/xhtml','a');
+ newnode.href = 'http://example.org';
+ newnode.accessKey = 'f';
+ detachedAccess = newnode.accessKeyLabel;
+ info('[new document] detached: ' + detachedAccess);
+ myDoc.appendChild(newnode);
+ attachedAcess = newnode.accessKeyLabel;
+ info('[new document] attached: ' + attachedAcess);
+ is(detachedAccess, attachedAcess, "Both values are same for the new Document()");
+
+</script>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1079236
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1079236</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1079236 **/
+
+ function runTests() {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML = '<div id="content"></div>';
+
+ var c = iframe.contentDocument.getElementById("content");
+ var sr = c.attachShadow({mode: 'open'});
+ sr.innerHTML = "<input type='file'" + ">";
+ var file = sr.firstChild;
+ is(file.type, "file");
+ file.offsetLeft; // Flush layout because dispatching mouse events.
+ iframe.contentDocument.body.onmousemove = function(e) {
+ is(e.target, c, "Event target should be the element in non-Shadow DOM");
+ if (e.originalTarget == file) {
+ is(e.originalTarget, file,
+ "type='file' implementation doesn't seem to have native anonymous content");
+ } else {
+ var wrapped = SpecialPowers.wrap(e.originalTarget);
+ isnot(wrapped, file, "Shouldn't have the same event.target and event.originalTarget");
+ }
+
+ ok(!("composedTarget" in e), "Events shouldn't have composedTarget in non-chrome context!");
+ e = SpecialPowers.wrap(e);
+ var composedTarget = SpecialPowers.unwrap(e.composedTarget);
+ is(composedTarget, file, "composedTarget should be the file object.");
+
+ SimpleTest.finish();
+ }
+
+ var r = file.getBoundingClientRect();
+ synthesizeMouse(file, r.width / 6, r.height / 2, { type: "mousemove"}, iframe.contentWindow);
+ iframe.contentDocument.body.onmousemove = null;
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ window.onload = () => {
+ SimpleTest.waitForFocus(runTests);
+ };
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1079236">Mozilla Bug 1079236</a>
+<p id="display"></p>
+<div id="content">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
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 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1127588
+-->
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1127588">Mozilla Bug 1127588</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<script type="application/javascript">
+
+/** Test for Bug 1127588 **/
+
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function () {
+ let insertedEventCount = 0;
+ let insertedListener = function() {
+ insertedEventCount++;
+ };
+
+ let removedEventCount = 0;
+ let removedListener = function() {
+ removedEventCount++;
+ };
+
+ // Tests for no title element.
+ document.addEventListener('DOMNodeRemoved', removedListener);
+ document.addEventListener('DOMNodeInserted', insertedListener);
+ document.title = "Test for Bug 1127588";
+ document.removeEventListener('DOMNodeInserted', insertedListener);
+ document.removeEventListener('DOMNodeRemoved', removedListener);
+
+ // Check result.
+ is(insertedEventCount, 2, "Should get 'DOMNodeInserted' mutation event");
+ is(removedEventCount, 0, "Should not get 'DOMNodeRemoved' mutation event");
+
+ // Test for updating title element.
+ insertedEventCount = 0;
+ removedEventCount = 0;
+ document.addEventListener('DOMNodeRemoved', removedListener);
+ document.addEventListener('DOMNodeInserted', insertedListener);
+ document.title = document.title;
+ document.removeEventListener('DOMNodeInserted', insertedListener);
+ document.removeEventListener('DOMNodeRemoved', removedListener);
+
+ // Check result.
+ is(insertedEventCount, 1, "Should get 'DOMNodeInserted' mutation event");
+ is(removedEventCount, 1, "Should get 'DOMNodeRemoved' mutation event");
+
+ SimpleTest.finish();
+};
+
+</script>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug1128787-1.html b/dom/events/test/test_bug1128787-1.html
new file mode 100644
index 0000000000..f6e7f27e86
--- /dev/null
+++ b/dom/events/test/test_bug1128787-1.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1128787
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1128787</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1128787 **/
+ SimpleTest.waitForExplicitFinish();
+
+ window.onload = function (aEvent) {
+ var blurEventFired = false;
+ var input = document.getElementsByTagName("input")[0];
+ input.addEventListener("blur", function (event) {
+ ok(true, "input element gets blur event correctly");
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ is(utils.IMEStatus, utils.IME_STATUS_ENABLED, "IME should be enabled");
+
+ SimpleTest.executeSoon(function () {
+ document.designMode = "off";
+
+ // XXX Should be fixed.
+ todo_is(utils.IMEStatus, utils.IME_STATUS_DISABLED, "IME should be disabled");
+
+ SimpleTest.finish();
+ });
+ }, {once: true});
+ document.designMode = "on";
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1128787">Mozilla Bug 1128787</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<input type="button"/>
+<script>
+var input = document.getElementsByTagName("input")[0];
+input.focus();
+</script>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1128787-2.html b/dom/events/test/test_bug1128787-2.html
new file mode 100644
index 0000000000..cb10ea431c
--- /dev/null
+++ b/dom/events/test/test_bug1128787-2.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1128787
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1128787</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1128787 **/
+ SimpleTest.waitForExplicitFinish();
+
+ window.onload = function (aEvent) {
+ var blurEventFired = false;
+ var input = document.getElementsByTagName("input")[0];
+ input.addEventListener("blur", function (event) {
+ ok(true, "input element gets blur event correctly");
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ is(utils.IMEStatus, utils.IME_STATUS_ENABLED, "IME should be enabled");
+
+ SimpleTest.executeSoon(function () {
+ document.designMode = "off";
+
+ // XXX Should be fixed.
+ todo_is(utils.IMEStatus, utils.IME_STATUS_DISABLED, "IME should be disabled");
+
+ SimpleTest.finish();
+ });
+ }, {once: true});
+ document.designMode = "on";
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1128787">Mozilla Bug 1128787</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<p contenteditable="true"></p>
+<input type="button"/>
+<script>
+var input = document.getElementsByTagName("input")[0];
+input.focus();
+</script>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1128787-3.html b/dom/events/test/test_bug1128787-3.html
new file mode 100644
index 0000000000..344439c244
--- /dev/null
+++ b/dom/events/test/test_bug1128787-3.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1128787
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1128787</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1128787 **/
+ SimpleTest.waitForExplicitFinish();
+
+ window.onload = function (aEvent) {
+ var blurEventFired = false;
+ var input = document.getElementsByTagName("input")[0];
+ input.addEventListener("blur", function (event) {
+ ok(true, "input element gets blur event correctly");
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ is(utils.IMEStatus, utils.IME_STATUS_ENABLED, "IME should be enabled");
+
+ is(document.designMode, "on",
+ "designMode should be \"on\" when blur event caused by enabling designMode is fired");
+ document.designMode = "off";
+ is(document.designMode, "off",
+ "designMode should become \"off\" even if it's reset by the blur event handler caused by enabling designMode");
+
+ todo_is(utils.IMEStatus, utils.IME_STATUS_DISABLED, "IME should be disabled");
+ SimpleTest.finish();
+ }, {once: true});
+ document.designMode = "on";
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1128787">Mozilla Bug 1128787</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<input type="button"/>
+<script>
+var input = document.getElementsByTagName("input")[0];
+input.focus();
+</script>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1145910.html b/dom/events/test/test_bug1145910.html
new file mode 100644
index 0000000000..2f7942937c
--- /dev/null
+++ b/dom/events/test/test_bug1145910.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1145910
+-->
+<head>
+ <title>Test for Bug 1145910</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript">
+
+/** Test for Bug 1145910 **/
+
+function runTests() {
+
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML =
+ '<style> div:active { color: rgb(0, 255, 0); } </style> <div id="host">Foo</div>';
+
+ var host = iframe.contentDocument.getElementById("host");
+ var shadow = host.attachShadow({mode: 'open'});
+ shadow.innerHTML = '<style>div:active { color: rgb(0, 255, 0); }</style><div id="inner">Bar</div>';
+ var inner = shadow.getElementById("inner");
+ var iframeWin = iframe.contentWindow;
+
+ is(iframeWin.getComputedStyle(host).color, "rgb(0, 0, 0)", "The host should not be active");
+ is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "The div inside the shadow root should not be active.");
+
+ synthesizeMouseAtCenter(host, { type: "mousedown" }, iframeWin);
+
+ is(iframeWin.getComputedStyle(inner).color, "rgb(0, 255, 0)", "Div inside shadow root should be active.");
+ is(iframeWin.getComputedStyle(host).color, "rgb(0, 255, 0)", "Host should be active when the inner div is made active.");
+
+ synthesizeMouseAtCenter(host, { type: "mouseup" }, iframeWin);
+
+ is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "Div inside shadow root should no longer be active.");
+ is(iframeWin.getComputedStyle(host).color, "rgb(0, 0, 0)", "Host should no longer be active.");
+
+ SimpleTest.finish();
+};
+
+SimpleTest.waitForExplicitFinish();
+window.onload = () => {
+ SimpleTest.waitForFocus(runTests);
+};
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1150308.html b/dom/events/test/test_bug1150308.html
new file mode 100644
index 0000000000..e9f9b480de
--- /dev/null
+++ b/dom/events/test/test_bug1150308.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1150308
+-->
+<head>
+ <title>Test for Bug 1150308</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript">
+
+/** Test for Bug 1150308 **/
+
+function runTests() {
+ var iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentDocument.body.innerHTML =
+ '<div id="host"><span id="distributeme">Foo</span></div>';
+
+ var host = iframe.contentDocument.getElementById("host");
+ var shadow = host.attachShadow({mode: 'open'});
+ shadow.innerHTML = '<style>.bar:active { color: rgb(0, 255, 0); }</style><div class="bar" id="inner"><slot></slot></div>';
+ var inner = shadow.getElementById("inner");
+ var distributed = iframe.contentDocument.getElementById("distributeme");
+ var iframeWin = iframe.contentWindow;
+
+ is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "The div inside the shadow root should not be active.");
+
+ synthesizeMouseAtCenter(distributed, { type: "mousedown" }, iframeWin);
+
+ is(iframeWin.getComputedStyle(inner).color, "rgb(0, 255, 0)", "Div inside shadow root should be active.");
+
+ synthesizeMouseAtCenter(distributed, { type: "mouseup" }, iframeWin);
+
+ is(iframeWin.getComputedStyle(inner).color, "rgb(0, 0, 0)", "Div inside shadow root should no longer be active.");
+
+ SimpleTest.finish();
+};
+
+SimpleTest.waitForExplicitFinish();
+window.onload = () => {
+ SimpleTest.waitForFocus(runTests);
+};
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1248459.html b/dom/events/test/test_bug1248459.html
new file mode 100644
index 0000000000..40aa162f7e
--- /dev/null
+++ b/dom/events/test/test_bug1248459.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1248459
+-->
+<head>
+ <title>Test for Bug 1248459</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<input id="input" value="foo">
+<div id="div">bar</div>
+<script type="application/javascript">
+
+/** Test for Bug 1248459 **/
+/**
+ * The bug occurs when a piece of text outside of the editor's root element is
+ * somehow selected when the editor is focused. In the bug's case, it's the
+ * placeholder anonymous div that's selected. In this test's case, it's a
+ * document div that's selected.
+ */
+SimpleTest.waitForExplicitFinish();
+
+SimpleTest.waitForFocus(function() {
+ var div = document.getElementById("div");
+ var input = document.getElementById("input");
+
+ input.appendChild(div);
+ input.focus();
+
+ var editor = SpecialPowers.wrap(input).editor;
+ var sel = editor.selection;
+
+ sel.selectAllChildren(editor.rootElement);
+ var result = synthesizeQuerySelectedText();
+
+ ok(result.succeeded, "Query selected text should succeed");
+ is(result.offset, 0, "Selected text should be at offset 0");
+ is(result.text, "foo", "Selected text should match");
+
+ var range = document.createRange();
+ range.selectNode(div);
+
+ sel.removeAllRanges();
+ sel.addRange(range);
+
+ result = synthesizeQuerySelectedText();
+
+ ok(!result.succeeded, "Query out-of-bounds selection should fail");
+
+ SimpleTest.finish();
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1264380.html b/dom/events/test/test_bug1264380.html
new file mode 100644
index 0000000000..9349e9712f
--- /dev/null
+++ b/dom/events/test/test_bug1264380.html
@@ -0,0 +1,82 @@
+<html>
+<head>
+ <title>Test the dragstart event on the anchor in side shadow DOM</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+<script>
+
+async function runTests()
+{
+ let dragService = SpecialPowers.Cc["@mozilla.org/widget/dragservice;1"].
+ getService(SpecialPowers.Ci.nsIDragService);
+
+ let iframe = document.querySelector("iframe");
+ let iframeDoc = iframe.contentDocument;
+ let iframeWin = iframe.contentWindow;
+
+ let shadow = iframeDoc.querySelector('#outer').attachShadow({mode: 'open'});
+
+ let target = iframeDoc.createElement('a');
+ target.textContent = "Drag me if you can!";
+ const URL = "http://www.mozilla.org/";
+ target.href = URL;
+ shadow.appendChild(target);
+
+ // Some of the drag data we don't actually care about for this test,
+ // so we'll use this comparator function to ignore them.
+ function ignoreFunc(actualData, expectedData) {
+ return true;
+ }
+
+ const EXPECTED_DRAG_DATA = [[{
+ type: "text/x-moz-url",
+ data: "",
+ eqTest: ignoreFunc,
+ }, {
+ type: "text/x-moz-url-data",
+ data: "",
+ eqTest: ignoreFunc,
+ }, {
+ type: "text/x-moz-url-desc",
+ data: "",
+ eqTest: ignoreFunc,
+ }, {
+ type: "text/uri-list",
+ data: URL,
+ }, {
+ type: "text/_moz_htmlinfo",
+ data: "",
+ eqTest: ignoreFunc,
+ }, {
+ type: "text/html",
+ data: "",
+ eqTest: ignoreFunc,
+ }, {
+ type: "text/plain",
+ data: URL,
+ }]];
+
+ let result = await synthesizePlainDragAndCancel(
+ {
+ srcElement: target,
+ srcWindow: iframeWin,
+ finalY: -10, // Avoid clicking the link
+ },
+ EXPECTED_DRAG_DATA);
+ ok(result === true, "Should have gotten the expected drag data.");
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+window.onload = () => {
+ SimpleTest.waitForFocus(runTests);
+};
+
+</script>
+
+<body>
+ <iframe srcdoc='<div id="outer"/>'></iframe>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1298970.html b/dom/events/test/test_bug1298970.html
new file mode 100644
index 0000000000..dc7c15a9d6
--- /dev/null
+++ b/dom/events/test/test_bug1298970.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1298970
+-->
+<head>
+ <title>Test for Bug 1298970</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1298970">Mozilla Bug 1298970</a>
+<p id="display"></p>
+<div id="inner"></div>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1298970 **/
+var target = document.getElementById("inner");
+var event = new Event("test", { bubbles: true, cancelable: true });
+
+is(event.cancelBubble, false, "Event.cancelBubble should be false by default");
+
+target.addEventListener("test", (e) => {
+ e.stopPropagation();
+ is(e.cancelBubble, true, "Event.cancelBubble should be true after stopPropagation");
+}, true);
+
+target.dispatchEvent(event);
+
+</script>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug1304044.html b/dom/events/test/test_bug1304044.html
new file mode 100644
index 0000000000..39eb39df15
--- /dev/null
+++ b/dom/events/test/test_bug1304044.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1304044
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1304044</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ var eventsFired = [];
+ var target;
+ var eventsExpected;
+
+ function GetNodeString(node) {
+ if (node == window)
+ return "window";
+ if (node == document)
+ return "document";
+ if (node.id)
+ return node.id;
+ if (node.nodeName)
+ return node.nodeName;
+ return node;
+ }
+
+ function TargetAndListener(listener, targetInner) {
+ this.listener = listener;
+ this.target = targetInner;
+ }
+
+ TargetAndListener.prototype.toString = function() {
+ var targetName = GetNodeString(this.target);
+ var listenerName = GetNodeString(this.listener);
+ return "(listener: " + listenerName + ", target: " + targetName + ")";
+ }
+
+ var tests = [
+ TestAuxClickBubblesForEventListener,
+ TestAuxClickBubblesForOnAuxClick,
+ ];
+
+ function CompareEvents(evt, expected) {
+ return evt && expected && evt.listener == expected.listener &&
+ evt.target == expected.target;
+ }
+
+ function ResetEventsFired() {
+ eventsFired = [];
+ }
+
+ function ClearEventListeners() {
+ for (i in arguments) {
+ arguments[i].removeEventListener("auxclick", log_event);
+ }
+ }
+
+ function ClickTarget(tgt) {
+ synthesizeMouseAtCenter(tgt, {type : "mousedown", button: 2}, window);
+ synthesizeMouseAtCenter(tgt, {type : "mouseup", button: 2}, window);
+ }
+
+ function log_event(e) {
+ eventsFired[eventsFired.length] = new TargetAndListener(this, e.target);
+ }
+
+ function CompareEventsToExpected(expected, actual) {
+ for (var i = 0; i < expected.length || i < actual.length; i++) {
+ ok(CompareEvents(actual[i], expected[i]),
+ "Auxclick receiver's don't match: TargetAndListener " +
+ i + ": Expected: " + expected[i] + ", Actual: " + actual[i]);
+ }
+ }
+
+ function TestAuxClickBubblesForEventListener() {
+ target.addEventListener("auxclick", log_event);
+ document.addEventListener("auxclick", log_event);
+ window.addEventListener("auxclick", log_event);
+
+ ClickTarget(target)
+ CompareEventsToExpected(eventsExpected, eventsFired);
+ ResetEventsFired();
+ ClearEventListeners(target, document, window);
+ }
+
+ function TestAuxClickBubblesForOnAuxClick() {
+ target.onauxclick = log_event;
+ document.onauxclick = log_event;
+ window.onauxclick = log_event;
+
+ ClickTarget(target);
+ CompareEventsToExpected(eventsExpected, eventsFired);
+ ResetEventsFired();
+ }
+
+ function RunTests(){
+ for (var i = 0; i < tests.length; i++) {
+ tests[i]();
+ }
+ }
+
+ function Begin() {
+ target = document.getElementById("target");
+ eventsExpected = [
+ new TargetAndListener(target, target),
+ new TargetAndListener(document, target),
+ new TargetAndListener(window, target),
+ ];
+ RunTests();
+ target.remove();
+ SimpleTest.finish();
+ }
+
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.executeSoon(Begin);
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1304044">Mozilla Bug 1304044</a>
+<p id="display">
+ <div id="target">Target</div>
+</p>
+<div id="content" style:"display:none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1305458.html b/dom/events/test/test_bug1305458.html
new file mode 100644
index 0000000000..a595502892
--- /dev/null
+++ b/dom/events/test/test_bug1305458.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1305458
+-->
+<head>
+ <title>Test for Bug 1305458</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ input[type=number] {
+ appearance: textfield;
+ }
+ input[type=number]:focus,
+ input[type=number]:hover {
+ appearance: auto;
+ }
+ </style>
+</head>
+<body onload="doTest()">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1305458">Mozilla Bug 1305458</a>
+ <input id="test_input" type="number">
+ <div id="test_div">bar</div>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ var change_count = 0;
+ function doTest() {
+ let input = document.getElementById("test_input");
+ let div = document.getElementById("test_div");
+ input.addEventListener("change", () => {
+ ++change_count;
+ });
+ // mouse hover
+ input.focus();
+ synthesizeMouse(input, 1, 1, {type: "mousemove"});
+ sendString("1");
+ input.blur();
+ is(change_count, 1, "input should fire change when blur");
+
+ input.focus();
+ synthesizeMouse(div, 1, 1, {type: "mousemove"});
+ sendString("1");
+ input.blur();
+ is(change_count, 2, "input should fire change when blur");
+ SimpleTest.finish();
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1327798.html b/dom/events/test/test_bug1327798.html
new file mode 100644
index 0000000000..9130353c75
--- /dev/null
+++ b/dom/events/test/test_bug1327798.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Test for bug 1327798</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?=id=1327798">Mozilla Bug 1327798</a>
+<p id="display"></p>
+<div id="content" style="display: none;"></div>
+
+<div contenteditable="true" id="editable1"><b>Formatted Text</b><br></div>
+<pre>
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(() => {
+ var editable = document.getElementById("editable1");
+ editable.focus();
+
+ window.getSelection().selectAllChildren(editable1);
+
+ SpecialPowers.doCommand(window, "cmd_copy");
+
+ //--------- now check the content of the clipboard
+ var clipboard = SpecialPowers.Cc["@mozilla.org/widget/clipboard;1"]
+ .getService(SpecialPowers.Ci.nsIClipboard);
+ // does the clipboard contain text/unicode data ?
+ ok(clipboard.hasDataMatchingFlavors(["text/unicode"], clipboard.kGlobalClipboard),
+ "clipboard contains unicode text");
+ // does the clipboard contain text/html data ?
+ ok(clipboard.hasDataMatchingFlavors(["text/html"], clipboard.kGlobalClipboard),
+ "clipboard contains html text");
+
+ window.addEventListener("paste", (e) => {
+ is(e.clipboardData.types.indexOf('text/html'), -1, "clipboardData shouldn't have text/html");
+ is(e.clipboardData.getData('text/plain'), "Formatted Text", "getData(text/plain) should return plain text");
+ SimpleTest.finish();
+ });
+
+ SpecialPowers.doCommand(window, "cmd_pasteNoFormatting");
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1332699.html b/dom/events/test/test_bug1332699.html
new file mode 100644
index 0000000000..c2a858d8ad
--- /dev/null
+++ b/dom/events/test/test_bug1332699.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test for bug 1332699</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<style>
+#test {
+ color: red;
+ transition: color 100ms;
+}
+#test.changed {
+ color: green;
+}
+</style>
+<div id="test"></div>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function () {
+ let $test = document.getElementById('test');
+ is(getComputedStyle($test).color, 'rgb(255, 0, 0)',
+ 'color should be red before transition');
+ let numEvents = 0;
+ $test.addEventListener('webkitTransitionEnd', function() {
+ ++numEvents;
+ if (numEvents == 1) {
+ is(getComputedStyle($test).color, 'rgb(0, 128, 0)',
+ 'color should be green after transition');
+ $test.dispatchEvent(new TransitionEvent('transitionend'));
+ is(numEvents, 1, "Shouldn't receive the prefixed event again");
+ SimpleTest.finish();
+ }
+ });
+ $test.className = 'changed';
+};
+</script>
diff --git a/dom/events/test/test_bug1339758.html b/dom/events/test/test_bug1339758.html
new file mode 100644
index 0000000000..0a437f57de
--- /dev/null
+++ b/dom/events/test/test_bug1339758.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1339758
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1339758</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1339758 **/
+ var expectNonZeroCoordinates = false;
+ SimpleTest.waitForExplicitFinish();
+
+ function testCoordinates(e) {
+ var coordinateProperties =
+ [ "screenX",
+ "screenY",
+ "clientX",
+ "clientY",
+ "offsetX",
+ "offsetY",
+ "movementX",
+ "movementY",
+ "layerX",
+ "layerY",
+ "x",
+ "y" ];
+ for (var i in coordinateProperties) {
+ if (e[coordinateProperties[i]] != 0) {
+ ok(expectNonZeroCoordinates, e.target.id + " got at least some non-zero coordinate property: " + i);
+ return;
+ }
+ }
+ ok(!expectNonZeroCoordinates, "Non-zero coordinates weren't expected");
+ }
+
+ function runTests() {
+ info("Testing click events which should have only 0 coordinates.");
+ document.getElementById("div_target").click();
+ document.getElementById("a_target").focus();
+ sendKey("RETURN");
+ document.getElementById("input_target").focus();
+ sendKey("RETURN");
+
+ info("Testing click events which should have also non-zero coordinates.");
+ expectNonZeroCoordinates = true;
+ // Test script created MouseEvents
+ sendMouseEvent({ type: "click"}, document.getElementById("a_target"));
+ sendMouseEvent({ type: "click"}, document.getElementById("input_target"));
+
+ // Test widget level mouse events
+ synthesizeMouse(document.getElementById("a_target"), 2, 2, {});
+ synthesizeMouse(document.getElementById("input_target"), 2, 2, {});
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForFocus(runTests);
+
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1339758">Mozilla Bug 1339758</a>
+<p id="display"></p>
+
+<div id="div_target" onclick="testCoordinates(event)">&nbsp;</div>
+<a href="#" id="a_target" onclick="testCoordinates(event);">test link</a><br>
+<input type="button" id="input_target" onclick="testCoordinates(event);" value="test button">
+
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1369072.html b/dom/events/test/test_bug1369072.html
new file mode 100644
index 0000000000..9f117c4902
--- /dev/null
+++ b/dom/events/test/test_bug1369072.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1369072
+-->
+<head>
+ <title>Test for Bug 1369072</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1369072">Mozilla Bug 1369072</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1369072 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var subWin = window.open("window_bug1369072.html", "_blank",
+ "width=500,height=500");
+
+function finish()
+{
+ subWin.close();
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1412775.xhtml b/dom/events/test/test_bug1412775.xhtml
new file mode 100644
index 0000000000..3146a489f1
--- /dev/null
+++ b/dom/events/test/test_bug1412775.xhtml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1412775
+-->
+<window title="Mozilla Bug 1412775"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="init()">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script src="chrome://mochikit/content/chrome-harness.js"></script>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 1412775 **/
+ var win;
+ function init() {
+ SimpleTest.waitForExplicitFinish();
+ win = window.browsingContext.topChromeWindow.open("window_bug1412775.xhtml", "_new", "chrome");
+ win.onload = function() {
+ var b = win.document.getElementById("browser");
+ var d = b.contentWindow.document;
+ var e = new d.defaultView.Event("foo");
+ var didCallChromeSide = false;
+ var didCallContentSide = false;
+ /* eslint-disable-next-line no-shadow */
+ b.addEventListener("foo", function(e) {
+ didCallChromeSide = true;
+ var path = e.composedPath();
+ var mm = d.defaultView.docShell.messageManager;
+ is(path.length, 5, "Should have 5 items in composedPath in chrome.");
+ is(path[0], mm, "BrowserChildGlobal is the chrome handler.");
+ is(path[1], b, "browser element should be in the path.");
+ is(path[2], b.parentNode, "window element should be in the path.");
+ is(path[3], win.document, "Document object should be in the path.");
+ is(path[4], win, "Window object should be in the path.");
+ }, true, true);
+ /* eslint-disable-next-line no-shadow */
+ d.addEventListener("foo", function(e) {
+ didCallContentSide = true;;
+ var path = e.composedPath();
+ is(path.length, 4, "Should have 4 items in composedPath in content.");
+ is(path[0], d.body, "body element should be in the path.");
+ is(path[1], d.documentElement, "html element should be in the path.");
+ is(path[2], d, "Document object should be in the path.");
+ is(path[3], d.defaultView, "Window object should be in the path.");
+ }, true, true);
+ d.body.dispatchEvent(e);
+ ok(didCallChromeSide, "didCallChromeSide");
+ ok(didCallContentSide, "didCallContentSide");
+ win.close();
+ SimpleTest.finish();
+ }
+ }
+
+ ]]>
+ </script>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1412775"
+ target="_blank">Mozilla Bug 1412775</a>
+ </body>
+</window>
diff --git a/dom/events/test/test_bug1429572.html b/dom/events/test/test_bug1429572.html
new file mode 100644
index 0000000000..d793a44fd9
--- /dev/null
+++ b/dom/events/test/test_bug1429572.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1429572
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1429572</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1429572 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var win;
+ function start() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_touch_events.enabled", 1],
+ ["dom.w3c_touch_events.legacy_apis.enabled", true]]},
+ function() {
+ ok(true, "Starting the test.");
+ win = window.open("window_bug1429572.html", "testwindow",
+ "width=" + window.screen.width +
+ ",height=" + window.screen.height);
+ });
+ }
+
+ function done() {
+ setTimeout("SimpleTest.finish();");
+ }
+
+ </script>
+</head>
+<body onload="start();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1429572">Mozilla Bug 1429572</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1446834.html b/dom/events/test/test_bug1446834.html
new file mode 100644
index 0000000000..495f9b4b3c
--- /dev/null
+++ b/dom/events/test/test_bug1446834.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1446834
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1446834</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1446834 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ window.onload = function() {
+ document.getElementById("iframe").src = "file_bug1446834.html";
+ }
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1446834">Mozilla Bug 1446834</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<iframe id="iframe"></iframe>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1447993.html b/dom/events/test/test_bug1447993.html
new file mode 100644
index 0000000000..b6951cc22f
--- /dev/null
+++ b/dom/events/test/test_bug1447993.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1447993
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1447993</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1447993 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var win;
+ function start() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.w3c_touch_events.enabled", 1]]},
+ function() {
+ win = window.open("window_bug1447993.html", "testwindow",
+ "width=" + window.screen.width +
+ ",height=" + window.screen.height);
+ });
+ }
+
+ function done() {
+ setTimeout("SimpleTest.finish();");
+ }
+
+ </script>
+</head>
+<body onload="start();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1447993">Mozilla Bug 1447993</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1484371.html b/dom/events/test/test_bug1484371.html
new file mode 100644
index 0000000000..c1b2a31217
--- /dev/null
+++ b/dom/events/test/test_bug1484371.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1484371
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1484371</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1484371 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ window.onload = function() {
+ document.getElementById("iframe").src = "file_bug1484371.html";
+ }
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1484371">Mozilla Bug 1484371</a>
+<iframe id="iframe"></iframe>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1518442.html b/dom/events/test/test_bug1518442.html
new file mode 100644
index 0000000000..d66846a578
--- /dev/null
+++ b/dom/events/test/test_bug1518442.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1518442</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+function runTest() {
+ var iframe = document.createElement("iframe");
+ iframe.src = "about:blank";
+ iframe.onload = () => frameLoaded(iframe);
+ document.body.appendChild(iframe);
+}
+
+function frameLoaded(iframe) {
+ let win = iframe.contentWindow;
+ let doc = iframe.contentDocument;
+ let element = iframe.contentDocument.documentElement;
+
+ is(win.onformdata, undefined, "Should not have window.onformdata");
+ is(doc.onformdata, undefined, "Should not have document.onformdata");
+ is(element.onformdata, undefined, "Should not have document.documentElement.onformdata");
+
+ let eventName = "formdata";
+ win.testValue = "not fired";
+ element.setAttribute("on" + eventName, "window.testValue = 'fired'");
+ element.dispatchEvent(new Event(eventName));
+ is(win.testValue, "not fired", `${eventName} should not have fired when pref disable`);
+
+ win.testValue = "not fired";
+ element.removeAttribute("on" + eventName);
+ element.dispatchEvent(new Event(eventName));
+ is(win.testValue, "not fired", `${eventName} should not have fired any event`);
+
+ delete win.testValue;
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["dom.formdata.event.enabled", false]]}, runTest);
+ </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1534562.html b/dom/events/test/test_bug1534562.html
new file mode 100644
index 0000000000..7ac6c31dd7
--- /dev/null
+++ b/dom/events/test/test_bug1534562.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1534562
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1534562</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1534562 **/
+
+ function runTest() {
+ var host = document.getElementById("host");
+ var shadow = host.attachShadow({mode: 'open'});
+ var shadowDiv = document.createElement('div');
+ shadowDiv.style.cssText = "height: 100%; width: 100%";
+ shadowDiv.onpointerdown = function (e) {
+ shadowDiv.setPointerCapture(e.pointerId);
+ };
+ var shadowDivGotPointerMove = false;
+ shadowDiv.onpointermove = function(e) {
+ shadowDivGotPointerMove = true;
+ }
+ shadow.appendChild(shadowDiv);
+ host.offsetLeft; // Flush layout.
+
+ synthesizeMouseAtCenter(shadowDiv, { type: "mousedown" });
+ synthesizeMouseAtCenter(document.getElementById("lightDOM"), { type: "mousemove" });
+ ok(shadowDivGotPointerMove, "shadowDiv should have got pointermove event.");
+ synthesizeMouseAtCenter(document.getElementById("lightDOM"), { type: "mouseup" });
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(runTest);
+
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1534562">Mozilla Bug 1534562</a>
+<div id="host" style="height: 50px; width: 50px;">
+</div>
+<div id="lightDOM" style="height: 50px; width: 50px;">
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1539497.html b/dom/events/test/test_bug1539497.html
new file mode 100644
index 0000000000..f042a5587e
--- /dev/null
+++ b/dom/events/test/test_bug1539497.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>bug 1539497</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ function runTest() {
+ var win = window.open("about:blank");
+ win.onload = function() {
+ is(win.navigator.maxTouchPoints, 5, "Should have max touch points");
+ win.close();
+ SimpleTest.finish();
+ }
+ }
+ function init() {
+ SpecialPowers.pushPrefEnv(
+ {"set": [["dom.w3c_pointer_events.enabled", true],
+ ["dom.maxtouchpoints.testing.value", 5]]}, runTest);
+ }
+ </script>
+</head>
+<body onload="init()">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1581192.html b/dom/events/test/test_bug1581192.html
new file mode 100644
index 0000000000..414de06313
--- /dev/null
+++ b/dom/events/test/test_bug1581192.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Redispatching test with PresShell</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<button>click me!</button>
+<script>
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async () => {
+ /**
+ * We have same tests in Event-dispatch-redispatch.html of WPT. However,
+ * it does not send the event to the main process. Therefore the reported
+ * crash couldn't reproduce.
+ */
+ await SpecialPowers.pushPrefEnv({set: [["test.events.async.enabled", true]]});
+ let button = document.querySelector("button");
+ let mouseupEvent;
+ button.addEventListener("mouseup", aNativeMouseUpEvent => {
+ ok(aNativeMouseUpEvent.isTrusted,"First mouseup event should be trusted");
+ mouseupEvent = aNativeMouseUpEvent;
+ try {
+ button.dispatchEvent(aNativeMouseUpEvent);
+ ok(false, "Dispatching trusted mouseup event which is being dispatched should throw an exception");
+ } catch (e) {
+ is(e.name, "InvalidStateError", "Trusted mouseup event which is being dispatched shouldn't be able to be dispatched");
+ }
+ }, {once: true});
+
+ button.addEventListener("click", aNativeClickEvent => {
+ ok(aNativeClickEvent.isTrusted, "First click event should be trusted");
+ try {
+ button.dispatchEvent(aNativeClickEvent);
+ ok(false, "Dispatching trusted click event which is being dispatched should throw an exception");
+ } catch (e) {
+ is(e.name, "InvalidStateError", "Trusted click event which is being dispatched shouldn't be able to be dispatched");
+ }
+ let mouseupEventFired = false;
+ button.addEventListener("mouseup", aDispatchedMouseUpEvent => {
+ ok(!aDispatchedMouseUpEvent.isTrusted, "Redispatched mouseup event shouldn't be trusted");
+ mouseupEventFired = true;
+ }, {once: true});
+ function onClick(aNonDispatchedClickEvent) {
+ ok(false, "Redispatched mouseup event shouldn't cause dispatching another click event");
+ }
+ button.addEventListener("click", onClick);
+ ok(mouseupEvent.isTrusted, "Received mouseup event should be trusted before redispatching from click event listener");
+ button.dispatchEvent(mouseupEvent);
+ ok(!mouseupEvent.isTrusted, "Received mouseup event shouldn't be trusted after redispatching");
+ ok(mouseupEventFired, "Redispatched mouseup event should've been received");
+ button.removeEventListener("click", onClick);
+ ok(aNativeClickEvent.isTrusted, "First click event should still be trusted even after redispatching mouseup event");
+ SimpleTest.finish();
+ }, {once: true});
+ synthesizeMouseAtCenter(button, {});
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1673434.html b/dom/events/test/test_bug1673434.html
new file mode 100644
index 0000000000..f9bb09c69e
--- /dev/null
+++ b/dom/events/test/test_bug1673434.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<!--
+bugzilla.mozilla.org/show_bug.cgi?id=1673434
+-->
+<head>
+<title>Test for bug 1673434</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1673434">Mozilla Bug 1673434</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<input type="checkbox">
+<input type="radio" name="group" value="foo">
+<input type="radio" name="group" value="bar" checked>
+<input type="text">
+<script>
+const utils = SpecialPowers.DOMWindowUtils;
+
+function test_events(element, resolve) {
+ element.addEventListener("input", () => {
+ is(utils.isHandlingUserInput, false,
+ "isHandlingUserInput is false on input event by element.click()");
+ }, { once: true });
+ element.addEventListener("change", () => {
+ is(utils.isHandlingUserInput, false,
+ "isHandlingUserInput is false on change event by element.click()");
+ resolve();
+ }, { once: true });
+
+ element.click();
+}
+
+add_task(function testCheckboxEvent() {
+ return new Promise(resolve => {
+ let element = document.querySelector("input[type=checkbox]");
+ test_events(element, resolve);
+ });
+});
+
+add_task(function testRadioEvent() {
+ return new Promise(resolve => {
+ let element = document.querySelector("input[type=radio]");
+ test_events(element, resolve);
+ });
+});
+
+add_task(function testUserInput() {
+ // setUserInput should be handled as user input.
+ //
+ // XXX <textarea> won't fire input event by setUserInput.
+ return new Promise(resolve => {
+ let element = document.querySelector("input[type=text]");
+ element.addEventListener("input", () => {
+ is(utils.isHandlingUserInput, true,
+ "isHandlingUserInput is true on input event by setUserInput");
+ }, { once: true });
+ element.addEventListener("change", () => {
+ is(utils.isHandlingUserInput, true,
+ "isHandlingUserInput is true on change event by setUserInput");
+ resolve();
+ }, { once: true });
+
+ SpecialPowers.wrap(element).setUserInput("a");
+ });
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug1686716.html b/dom/events/test/test_bug1686716.html
new file mode 100644
index 0000000000..8779413a1a
--- /dev/null
+++ b/dom/events/test/test_bug1686716.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>bug 1686716</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ function test() {
+ var ifr = document.getElementsByTagName("iframe")[0];
+ ifr.contentWindow.addEventListener("drop",
+ function(event) {
+ ifr.remove();
+ event.preventDefault();
+ });
+ sendDragEvent({type: "drop"}, ifr.contentDocument.body, ifr.contentWindow);
+ ok(true, "Should not crash.");
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body onload="test()">
+<iframe></iframe>
+<p id="display"></p>
+</body>
+</html>
diff --git a/dom/events/test/test_bug226361.xhtml b/dom/events/test/test_bug226361.xhtml
new file mode 100644
index 0000000000..143a485757
--- /dev/null
+++ b/dom/events/test/test_bug226361.xhtml
@@ -0,0 +1,82 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=226361
+-->
+<head>
+ <title>Test for Bug 226361</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body id="body1">
+<p id="display">
+
+ <a id="b1" tabindex="1" href="http://home.mozilla.org">start</a><br />
+<br />
+
+<iframe id="iframe" tabindex="2" src="bug226361_iframe.xhtml"></iframe>
+
+ <a id="b2" tabindex="3" href="http://home.mozilla.org">end</a>
+
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 226361 **/
+
+// accessibility.tabfocus must be set to value 7 before running test also
+// on a mac.
+function setTabFocus() {
+ SpecialPowers.pushPrefEnv({ set: [[ "accessibility.tabfocus", 7 ]] }, doTest);
+}
+
+// =================================
+
+var doc = document;
+function tab_to(id) {
+ synthesizeKey("KEY_Tab", {});
+ is(doc.activeElement.id, id, "element with id=" + id + " should have focus");
+}
+
+function tab_iframe() {
+ doc = document;
+ tab_to('iframe');
+
+ // inside iframe
+ doc = document.getElementById('iframe').contentDocument
+ tab_to('a3');tab_to('a5');tab_to('a1');tab_to('a2');tab_to('a4');
+}
+
+
+function doTest() {
+ window.getSelection().removeAllRanges();
+ document.getElementById('body1').focus();
+ is(document.activeElement.id, document.body.id, "body element should be focused");
+
+ doc = document;
+ tab_to('b1');
+
+ tab_iframe();
+
+ doc=document
+ document.getElementById('iframe').focus()
+ tab_to('b2');
+ // Change tabindex so the next TAB goes back to the IFRAME
+ document.getElementById('iframe').setAttribute('tabindex','4');
+
+ tab_iframe();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(setTabFocus);
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug238987.html b/dom/events/test/test_bug238987.html
new file mode 100644
index 0000000000..3a7b12653b
--- /dev/null
+++ b/dom/events/test/test_bug238987.html
@@ -0,0 +1,279 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=238987
+-->
+<head>
+ <title>Test for Bug 238987</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=238987">Mozilla Bug 238987</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ /** Test for Bug 238987 **/
+
+ var shouldStop = false;
+ var activateShift = false;
+ var expectedResult = "i1,i2,i3,i4,i5,i6,i7,i8,number,i9,i10,i11,i12";
+ var forwardFocusArray = expectedResult.split(",");
+ var backwardFocusArray = expectedResult.split(",");
+ var forwardBlurArray = expectedResult.split(",");
+ var backwardBlurArray = expectedResult.split(",");
+ // Adding 3 for "begin", "end", "begin" and one for the <a> in the Mochitest template,
+ var expectedWindowFocusCount = forwardFocusArray.length + backwardFocusArray.length + 4;
+ // but the last blur event goes to i1, not "begin".
+ var expectedWindowBlurCount = forwardFocusArray.length + backwardFocusArray.length + 3;
+
+ function handleFocus(e) {
+ if (e.target.id == "begin") {
+ // if the activateShift is set, the test is coming back from the end.
+ if (activateShift) {
+ shouldStop = true;
+ }
+ } else if (e.target.id == "end") {
+ activateShift = true;
+ } else if (activateShift) {
+ var expected = backwardFocusArray.pop();
+ ok(expected == e.target.id,
+ "(focus) Backward tabbing, expected [" +
+ expected + "], got [" + e.target.id + "]");
+ } else {
+ var expected = forwardFocusArray.shift();
+ is(e.target, document.activeElement, "Wrong activeElement!");
+ ok(expected == e.target.id,
+ "(focus) Forward tabbing, expected [" +
+ expected + "], got [" + e.target.id + "]");
+ }
+ }
+
+ function handleWindowFocus(e) {
+ --expectedWindowFocusCount;
+ var s = "target " + e.target;
+ if ("id" in e.target) {
+ s = s + ", id=\"" + e.target.id + "\"";
+ }
+ ok(e.eventPhase == Event.CAPTURING_PHASE,
+ "|window| should not have got a focus event, " + s);
+ }
+
+ function handleBlur(e) {
+ if (e.target.id == "begin" || e.target.id == "end") {
+ return;
+ } else if (activateShift) {
+ var expected = backwardBlurArray.pop();
+ ok(expected == e.target.id,
+ "(blur) backward tabbing, expected [" +
+ expected + "], got [" + e.target.id + "]");
+ } else {
+ var expected = forwardBlurArray.shift();
+ ok(expected == e.target.id,
+ "(blur) forward tabbing, expected [" +
+ expected + "], got [" + e.target.id + "]");
+ }
+ }
+
+ function handleWindowBlur(e) {
+ --expectedWindowBlurCount;
+ var s = "target " + e.target;
+ if ("id" in e.target) {
+ s = s + ", id=\"" + e.target.id + "\"";
+ }
+ ok(e.eventPhase == Event.CAPTURING_PHASE,
+ "|window| should not have got a blur event, " + s);
+ }
+
+ function tab() {
+ // Send tab key events.
+ synthesizeKey("KEY_Tab", {shiftKey: activateShift});
+ if (shouldStop) {
+ // Did focus handling succeed
+ is(forwardFocusArray.length, 0,
+ "Not all forward tabbing focus tests were run, " +
+ forwardFocusArray.toString());
+ is(backwardFocusArray.length, 0,
+ "Not all backward tabbing focus tests were run, " +
+ backwardFocusArray.toString());
+ is(expectedWindowFocusCount, 0,
+ "|window| didn't get the right amount of focus events");
+
+ // and blur.
+ is(forwardBlurArray.length, 0,
+ "Not all forward tabbing blur tests were run, " +
+ forwardBlurArray.toString());
+ is(backwardBlurArray.length, 0,
+ "Not all backward tabbing blur tests were run, " +
+ backwardBlurArray.toString());
+ is(expectedWindowBlurCount, 0,
+ "|window| didn't get the right amount of blur events");
+
+ // Cleanup
+ window.removeEventListener("focus", handleWindowFocus, true);
+ window.removeEventListener("focus", handleWindowFocus);
+ window.removeEventListener("blur", handleWindowBlur, true);
+ window.removeEventListener("blur", handleWindowBlur);
+ var elements = document.getElementsByTagName("*");
+ for (var i = 0; i < elements.length; ++i) {
+ if (elements[i].hasAttribute("id")) {
+ elements[i].removeEventListener("focus", handleFocus);
+ elements[i].removeEventListener("blur", handleBlur);
+ }
+ }
+
+ SimpleTest.finish();
+ } else {
+ setTimeout(tab, 0);
+ }
+ }
+
+ function start() {
+ window.focus();
+ window.addEventListener("focus", handleWindowFocus, true);
+ window.addEventListener("focus", handleWindowFocus);
+ window.addEventListener("blur", handleWindowBlur, true);
+ window.addEventListener("blur", handleWindowBlur);
+ var elements = document.getElementsByTagName("*");
+ for (var i = 0; i < elements.length; ++i) {
+ if (elements[i].hasAttribute("id")) {
+ elements[i].addEventListener("focus", handleFocus);
+ elements[i].addEventListener("blur", handleBlur);
+ }
+ if (elements[i].getAttribute("tabindex") == "1") {
+ elements[i].setAttribute("tabindex", "-1");
+ }
+ }
+ tab();
+ }
+
+ // accessibility.tabfocus must be set to value 7 before running test also
+ // on a mac.
+ function doTest() {
+ SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]}, start);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+
+</script>
+</pre>
+ <h4 tabindex="0" id="begin">Test:</h4>
+ <table>
+ <tbody>
+ <tr>
+ <td>type="text"</td><td><input type="text" id="i1" value=""></td>
+ </tr>
+ <tr>
+ <td>type="button"</td><td><input type="button" id="i2" value="type='button'"></td>
+ </tr>
+ <tr>
+ <td>type="checkbox"</td><td><input type="checkbox" id="i3" ></td>
+ </tr>
+ <tr>
+ <td>type="radio" checked</td><td><input type="radio" id="i4" name="radio" checked>
+ <input type="radio" id="i4b" name="radio"></td>
+ </tr>
+ <tr>
+ <td>type="radio"</td><td><input type="radio" id="i5" name="radio2">
+ <input type="radio" id="i6" name="radio2"></td>
+ </tr>
+ <tr>
+ <td>type="password"</td><td><input type="password" id="i7"></td>
+ </tr>
+ <tr>
+ <td>type="file"</td><td><input type="file" id="i8"></td>
+ </tr>
+ <tr>
+ <td>type="number"</td><td><input type="number" id="number"></td>
+ </tr>
+ <tr>
+ <td>button</td><td><button id="i9">button</button></td>
+ </tr>
+ <tr>
+ <td>select</td><td><select id="i10"><option>select</option></select></td>
+ </tr>
+ <tr>
+ <td>a</td><td><a href="#radio" id="i11">a link</a></td>
+ </tr>
+ <tr>
+ <td>tabindex="0"</td><td><span tabindex="0" id="i12">span</span></td>
+ </tr>
+
+ <tr>
+ <td><h3>Form elements with tabindex="-1"</h3></td>
+ </tr>
+ <tr>
+ <td>type="text"</td><td><input type="text" tabindex="-1" value=""></td>
+ </tr>
+ <tr>
+ <td>type="button"</td><td><input type="button" tabindex="-1" value="type='button'"></td>
+ </tr>
+ <tr>
+ <td>type="checkbox"</td><td><input type="checkbox" tabindex="-1"></td>
+ </tr>
+ <tr>
+ <td>type="radio" checked</td><td><input type="radio" tabindex="-1" name="radio3" checked>
+ <input type="radio" tabindex="-1" name="radio3"></td>
+ </tr>
+ <tr>
+ <td>type="radio"</td><td><input type="radio" tabindex="-1" name="radio4">
+ <input type="radio" tabindex="-1" name="radio4"></td>
+ </tr>
+ <tr>
+ <td>type="password"</td><td><input type="password" tabindex="-1"></td>
+ </tr>
+ <tr>
+ <td>type="file"</td><td><input type="file" tabindex="-1"></td>
+ </tr>
+ <tr>
+ <td>button</td><td><button tabindex="-1">button</button></td>
+ </tr>
+ <tr>
+ <td>select</td><td><select tabindex="-1"><option>select</option></select></td>
+ </tr>
+
+ <tr>
+ <td><h3>Form elements with .setAttribute("tabindex", "-1")</h3></td>
+ </tr>
+ <tr>
+ <td>type="text"</td><td><input type="text" tabindex="1" value=""></td>
+ </tr>
+ <tr>
+ <td>type="button"</td><td><input type="button" tabindex="1" value="type='button'"></td>
+ </tr>
+ <tr>
+ <td>type="checkbox"</td><td><input type="checkbox" tabindex="1"></td>
+ </tr>
+ <tr>
+ <td>type="radio" checked</td><td><input type="radio" tabindex="1" name="radio5" checked>
+ <input type="radio" tabindex="1" name="radio5"></td>
+ </tr>
+ <tr>
+ <td>type="radio"</td><td><input type="radio" tabindex="1" name="radio6">
+ <input type="radio" tabindex="1" name="radio6"></td>
+ </tr>
+ <tr>
+ <td>type="password"</td><td><input type="password" tabindex="1"></td>
+ </tr>
+ <tr>
+ <td>type="file"</td><td><input type="file" tabindex="1"></td>
+ </tr>
+ <tr>
+ <td>button</td><td><button tabindex="1">button</button></td>
+ </tr>
+ <tr>
+ <td>select</td><td><select tabindex="1"><option>select</option></select></td>
+ </tr>
+
+ </tbody>
+ </table>
+ <h4 tabindex="0" id="end">done.</h4>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug288392.html b/dom/events/test/test_bug288392.html
new file mode 100644
index 0000000000..f50327eed3
--- /dev/null
+++ b/dom/events/test/test_bug288392.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=288392
+-->
+<head>
+ <title>Test for Bug 288392</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=288392">Mozilla Bug 288392</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<div id="mutationTarget">
+</div>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 288392 **/
+var subtreeModifiedCount;
+
+function subtreeModified(e)
+{
+ ++subtreeModifiedCount;
+}
+
+function doTest() {
+ var targetNode = document.getElementById("mutationTarget");
+ targetNode.addEventListener("DOMSubtreeModified", subtreeModified);
+
+ subtreeModifiedCount = 0;
+ var temp = document.createElement("DIV");
+ targetNode.appendChild(temp);
+ is(subtreeModifiedCount, 1,
+ "Appending a child node should have dispatched a DOMSubtreeModified event");
+
+ subtreeModifiedCount = 0;
+ temp.setAttribute("foo", "bar");
+ is(subtreeModifiedCount, 1,
+ "Setting an attribute should have dispatched a DOMSubtreeModified event");
+
+ subtreeModifiedCount = 0;
+ targetNode.removeChild(temp);
+ is(subtreeModifiedCount, 1,
+ "Removing a child node should have dispatched a DOMSubtreeModified event");
+
+ // Testing events in a subtree, which is not in the document.
+ var subtree = document.createElement("div");
+ var s = "<e1 attr1='value1'>Something1</e1><e2 attr2='value2'>Something2</e2>";
+ subtree.innerHTML = s;
+ subtree.addEventListener("DOMSubtreeModified", subtreeModified);
+
+ subtreeModifiedCount = 0;
+ subtree.firstChild.firstChild.data = "foo";
+ is(subtreeModifiedCount, 1,
+ "Editing character data should have dispatched a DOMSubtreeModified event");
+
+ subtreeModifiedCount = 0;
+ subtree.firstChild.removeChild(subtree.firstChild.firstChild);
+ is(subtreeModifiedCount, 1,
+ "Removing a child node should have dispatched a DOMSubtreeModified event");
+
+ subtree.innerHTML = s;
+ subtreeModifiedCount = 0;
+ subtree.firstChild.firstChild.remove();
+ is(subtreeModifiedCount, 1,
+ "Removing a child node should have dispatched a DOMSubtreeModified event");
+
+ subtreeModifiedCount = 0;
+ subtree.firstChild.setAttribute("foo", "bar");
+ is(subtreeModifiedCount, 1,
+ "Setting an attribute should have dispatched a DOMSubtreeModified event");
+
+ subtreeModifiedCount = 0;
+ subtree.textContent = "foobar";
+ is(subtreeModifiedCount, 1,
+ "Setting .textContent should have dispatched a DOMSubtreeModified event");
+
+ subtreeModifiedCount = 0;
+ subtree.innerHTML = s;
+ is(subtreeModifiedCount, 1,
+ "Setting .innerHTML should have dispatched a DOMSubtreeModified event");
+
+ subtreeModifiedCount = 0;
+ subtree.removeEventListener("DOMSubtreeModified", subtreeModified);
+ subtree.appendChild(document.createTextNode(""));
+ subtree.addEventListener("DOMSubtreeModified", subtreeModified);
+ subtree.normalize();
+ is(subtreeModifiedCount, 1,
+ "Calling normalize() should have dispatched a DOMSubtreeModified event");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+addLoadEvent(SimpleTest.finish);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug299673-1.html b/dom/events/test/test_bug299673-1.html
new file mode 100644
index 0000000000..c3662cc9b2
--- /dev/null
+++ b/dom/events/test/test_bug299673-1.html
@@ -0,0 +1,61 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=299673
+-->
+<head>
+ <title>Test #1 for Bug 299673</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body id="Body">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=299673">Mozilla Bug 299673</a>
+<p id="display">
+
+ <SELECT id="Select1" onchange="log(event); OpenWindow()" onfocus="log(event); " onblur="log(event)">
+ <OPTION selected>option1</OPTION>
+ <OPTION>option2</OPTION>
+ <OPTION>option3</OPTION>
+ </SELECT>
+
+ <INPUT id="Text1" type="text" onfocus="log(event)" onblur="log(event)">
+ <INPUT id="Text2" type="text" onfocus="log(event)" onblur="log(event)">
+
+</p>
+<div id="content" style="display: none">
+
+</div>
+
+<pre id="test">
+
+<script src="bug299673.js"></script>
+
+<script class="testbody" type="text/javascript">
+
+/** Test #1 for Bug 299673 **/
+function doTest(expectedEventLog) {
+ var eventLogForNewWindow = '\
+ : Test with browser.link.open_newwindow = 2\n\
+: focus top-doc\n\
+SELECT(Select1): focus \n\
+SELECT(Select1): change \n\
+ : >>> OpenWindow\n\
+: blur top-doc\n\
+: focus popup-doc\n\
+INPUT(popupText1): focus \n\
+ : <<< OpenWindow\n\
+SELECT(Select1): blur \n\
+INPUT(popupText1): blur \n\
+: blur popup-doc\n\
+: focus top-doc\n\
+'
+
+ setPrefAndDoTest(eventLogForNewWindow,'Body',2); // 2 = open new window as window
+}
+
+todo(false, "Please write a test for bug 299673 that actually works, see bug 553417");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug299673-2.html b/dom/events/test/test_bug299673-2.html
new file mode 100644
index 0000000000..c26a08009f
--- /dev/null
+++ b/dom/events/test/test_bug299673-2.html
@@ -0,0 +1,60 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=299673
+-->
+<head>
+ <title>Test #2 for Bug 299673</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body id="Body">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=299673">Mozilla Bug 299673</a>
+<p id="display">
+
+ <SELECT id="Select1" onchange="log(event); OpenWindow()" onfocus="log(event); " onblur="log(event)">
+ <OPTION selected>option1</OPTION>
+ <OPTION>option2</OPTION>
+ <OPTION>option3</OPTION>
+ </SELECT>
+
+ <INPUT id="Text1" type="text" onfocus="log(event)" onblur="log(event)">
+ <INPUT id="Text2" type="text" onfocus="log(event)" onblur="log(event)">
+
+</p>
+<div id="content" style="display: none">
+
+</div>
+
+<pre id="test">
+
+<script src="bug299673.js"></script>
+
+<script class="testbody" type="text/javascript">
+
+/** Test #2 for Bug 299673 **/
+function doTest(expectedEventLog) {
+ var eventLogForNewTab = '\
+ : Test with browser.link.open_newwindow = 3\n\
+: focus top-doc\n\
+SELECT(Select1): focus \n\
+SELECT(Select1): change \n\
+ : >>> OpenWindow\n\
+: blur top-doc\n\
+: focus popup-doc\n\
+INPUT(popupText1): focus \n\
+ : <<< OpenWindow\n\
+SELECT(Select1): blur \n\
+INPUT(popupText1): blur \n\
+: blur popup-doc\n\
+: focus top-doc\n\
+'
+ setPrefAndDoTest(eventLogForNewTab,'Body',3); // 3 = open new window as tab
+}
+
+todo(false, "Please write a test for bug 299673 that actually works, see bug 553417");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug322588.html b/dom/events/test/test_bug322588.html
new file mode 100644
index 0000000000..25008cb375
--- /dev/null
+++ b/dom/events/test/test_bug322588.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=322588
+-->
+<head>
+ <title>Test for Bug 322588 - onBlur window close no longer works</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=322588">Mozilla Bug 322588 - onBlur window close no longer works</a>
+<p id="display">
+<a id="link" href="javascript:pop350d('bug322588-popup.html#target')">Openwindow</a><br>
+The opened window should not directly close when clicking on the Openwindow link
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 322588 **/
+
+var result = "";
+
+var w;
+function pop350d(url) {
+ w = window.open();
+ w.addEventListener("unload", function () { result += " unload";});
+ w.addEventListener("load", function () { result += " load"; setTimeout(done, 1000);});
+ w.addEventListener("blur", function () { result += " blur";});
+ w.location = url;
+}
+
+function doTest() {
+ try {
+ sendMouseEvent({type:'click'}, 'link');
+ } catch(e) {
+ if (w)
+ w.close();
+ throw e;
+ }
+}
+
+function done() {
+ is(result," unload load","unexpected events"); // The first unload is for about:blank
+ if (w)
+ w.close();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+addLoadEvent(function() {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["browser.newtab.preload", false]
+ ]}, doTest);
+});
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug328885.html b/dom/events/test/test_bug328885.html
new file mode 100644
index 0000000000..1a41a305cf
--- /dev/null
+++ b/dom/events/test/test_bug328885.html
@@ -0,0 +1,132 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=328885
+-->
+<head>
+ <title>Test for Bug 328885</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=328885">Mozilla Bug 328885</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<input type="text" id="inputelement"
+ style="position: absolute; left: 0px; top: 0px;">
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 328885 **/
+
+ var inputelement = null;
+ var mutationCount = 0;
+
+ function mutationListener(evt) {
+ ++mutationCount;
+ }
+
+ function clickTest() {
+ inputelement.addEventListener("DOMSubtreeModified", mutationListener);
+ inputelement.addEventListener("DOMNodeInserted", mutationListener);
+ inputelement.addEventListener("DOMNodeRemoved", mutationListener);
+ inputelement.addEventListener("DOMNodeRemovedFromDocument", mutationListener);
+ inputelement.addEventListener("DOMNodeInsertedIntoDocument", mutationListener);
+ inputelement.addEventListener("DOMAttrModified", mutationListener);
+ inputelement.addEventListener("DOMCharacterDataModified", mutationListener);
+
+ inputelement.addEventListener('click',
+ function(event) {
+ var evt = SpecialPowers.wrap(event);
+ ok(SpecialPowers.unwrap(evt.originalTarget) instanceof HTMLDivElement,
+ "(1) Wrong originalTarget!");
+ is(SpecialPowers.unwrap(evt.originalTarget.parentNode), inputelement,
+ "(2) Wront parent node!");
+ ok(mutationCount == 0, "(3) No mutations should have happened! [" + mutationCount + "]");
+ evt.originalTarget.textContent = "foo";
+ ok(mutationCount == 0, "(4) Mutation listener shouldn't have been called! [" + mutationCount + "]");
+ evt.originalTarget.innerHTML = "foo2";
+ ok(mutationCount == 0, "(5) Mutation listener shouldn't have been called! [" + mutationCount + "]");
+ evt.originalTarget.lastChild.data = "bar";
+ ok(mutationCount == 0, "(6) Mutation listener shouldn't have been called! [" + mutationCount + "]");
+
+ var r = SpecialPowers.wrap(document.createRange());
+ r.selectNodeContents(evt.originalTarget);
+ r.deleteContents();
+ ok(mutationCount == 0, "(7) Mutation listener shouldn't have been called! [" + mutationCount + "]");
+
+ evt.originalTarget.textContent = "foo";
+ ok(mutationCount == 0, "(8) Mutation listener shouldn't have been called! [" + mutationCount + "]");
+ r = SpecialPowers.wrap(document.createRange());
+ r.selectNodeContents(evt.originalTarget);
+ r.extractContents();
+ ok(mutationCount == 0, "(9) Mutation listener shouldn't have been called! [" + mutationCount + "]");
+
+ evt.originalTarget.setAttribute("foo", "bar");
+ ok(mutationCount == 0, "(10) Mutation listener shouldn't have been called! ["+ mutationCount + "]");
+
+ // Same tests with non-native-anononymous element.
+ // mutationCount should be increased by 2 each time, since there is
+ // first a mutation specific event and then DOMSubtreeModified.
+ inputelement.textContent = "foo";
+ ok(mutationCount == 2, "(11) Mutation listener should have been called! [" + mutationCount + "]");
+ inputelement.lastChild.data = "bar";
+ ok(mutationCount == 4, "(12) Mutation listener should have been called! [" + mutationCount + "]");
+
+ r = document.createRange();
+ r.selectNodeContents(inputelement);
+ r.deleteContents();
+ ok(mutationCount == 6, "(13) Mutation listener should have been called! [" + mutationCount + "]");
+
+ inputelement.textContent = "foo";
+ ok(mutationCount == 8, "(14) Mutation listener should have been called! [" + mutationCount + "]");
+ r = document.createRange();
+ r.selectNodeContents(inputelement);
+ r.extractContents();
+ ok(mutationCount == 10, "(15) Mutation listener should have been called! [" + mutationCount + "]");
+
+ inputelement.setAttribute("foo", "bar");
+ ok(mutationCount == 12, "(16) Mutation listener should have been called! ["+ mutationCount + "]");
+
+ // Then try some mixed mutations. The mutation handler of non-native-a
+ inputelement.addEventListener("DOMAttrModified",
+ function (evt2) {
+ evt.originalTarget.setAttribute("foo", "bar" + mutationCount);
+ ok(evt.originalTarget.getAttribute("foo") == "bar" + mutationCount,
+ "(17) Couldn't update the attribute?!?");
+ });
+ inputelement.setAttribute("foo", "");
+ ok(mutationCount == 14, "(18) Mutation listener should have been called! ["+ mutationCount + "]");
+
+ inputelement.textContent = "foo";
+ ok(mutationCount == 16, "(19) Mutation listener should have been called! ["+ mutationCount + "]");
+ inputelement.addEventListener("DOMCharacterDataModified",
+ function (evt2) {
+ evt.originalTarget.textContent = "bar" + mutationCount;
+ });
+ // This one deletes and inserts a new node, then DOMSubtreeModified.
+ inputelement.textContent = "bar";
+ ok(mutationCount == 19, "(20) Mutation listener should have been called! ["+ mutationCount + "]");
+ });
+ synthesizeMouseAtCenter(inputelement, {}, window);
+ SimpleTest.finish();
+ }
+
+ function doTest() {
+ inputelement = document.getElementById('inputelement');
+ inputelement.focus();
+ setTimeout(clickTest, 100);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ addLoadEvent(doTest);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug336682.js b/dom/events/test/test_bug336682.js
new file mode 100644
index 0000000000..c7ca96c435
--- /dev/null
+++ b/dom/events/test/test_bug336682.js
@@ -0,0 +1,96 @@
+/*
+ * Helper functions for online/offline events tests.
+ *
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+var gState = 0;
+/**
+ * After all the on/offline handlers run,
+ * gState is expected to be equal to MAX_STATE.
+ */
+var MAX_STATE;
+
+function trace(text) {
+ var t = text.replace(/&/g, "&" + "amp;").replace(/</g, "&" + "lt;") + "<br>";
+ //document.getElementById("display").innerHTML += t;
+}
+
+/**
+ * Returns a handler function for an online/offline event. The returned handler
+ * ensures the passed event object has expected properties and that the handler
+ * is called at the right moment (according to the gState variable).
+ * @param nameTemplate The string identifying the hanlder. '%1' in that
+ * string will be replaced with the event name.
+ * @param eventName 'online' or 'offline'
+ * @param expectedStates an array listing the possible values of gState at the
+ * moment the handler is called. The handler increases
+ * gState by one before checking if it's listed in
+ * expectedStates.
+ */
+function makeHandler(nameTemplate, eventName, expectedStates) {
+ return function(e) {
+ var name = nameTemplate.replace(/%1/, eventName);
+ ++gState;
+ trace(name + ": gState=" + gState);
+ ok(
+ expectedStates.includes(gState),
+ "handlers called in the right order: " +
+ name +
+ " is called, " +
+ "gState=" +
+ gState +
+ ", expectedStates=" +
+ expectedStates
+ );
+ ok(e.constructor == Event, "event should be an Event");
+ ok(e.type == eventName, "event type should be " + eventName);
+ ok(!e.bubbles, "event should not bubble");
+ ok(!e.cancelable, "event should not be cancelable");
+ ok(e.target == window, "target should be the window");
+ };
+}
+
+function doTest() {
+ var iosvc = SpecialPowers.Cc["@mozilla.org/network/io-service;1"].getService(
+ SpecialPowers.Ci.nsIIOService
+ );
+ iosvc.manageOfflineStatus = false;
+ iosvc.offline = false;
+ ok(
+ navigator.onLine,
+ "navigator.onLine should be true, since we've just " +
+ "set nsIIOService.offline to false"
+ );
+
+ gState = 0;
+
+ trace("setting iosvc.offline = true");
+ iosvc.offline = true;
+ trace("done setting iosvc.offline = true");
+ ok(
+ !navigator.onLine,
+ "navigator.onLine should be false when iosvc.offline == true"
+ );
+ ok(
+ gState == window.MAX_STATE,
+ "offline event: all registered handlers should have been invoked, " +
+ "actual: " +
+ gState
+ );
+
+ gState = 0;
+ trace("setting iosvc.offline = false");
+ iosvc.offline = false;
+ trace("done setting iosvc.offline = false");
+ ok(
+ navigator.onLine,
+ "navigator.onLine should be true when iosvc.offline == false"
+ );
+ ok(
+ gState == window.MAX_STATE,
+ "online event: all registered handlers should have been invoked, " +
+ "actual: " +
+ gState
+ );
+}
diff --git a/dom/events/test/test_bug336682_1.html b/dom/events/test/test_bug336682_1.html
new file mode 100644
index 0000000000..7d3ef6b345
--- /dev/null
+++ b/dom/events/test/test_bug336682_1.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Bug 336682: online/offline events tests.
+
+Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/licenses/publicdomain/
+-->
+<head>
+ <title>Test for Bug 336682 (online/offline events)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body ononline="trace('<body ononline=...>');
+ bodyOnonline(this, event)"
+ onoffline="trace('<body onoffline=...>'); bodyOnoffline(this, event)"
+ >
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=336682">Mozilla Bug 336682</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<script type="text/javascript" src="test_bug336682.js"></script>
+
+<script class="testbody" type="text/javascript">
+
+function makeBodyHandler(eventName) {
+ return function (aThis, aEvent) {
+ var handler = makeHandler("<body on%1='...'>", eventName, [1]);
+ handler(aEvent);
+ }
+}
+addLoadEvent(function() {
+ /** @see test_bug336682.js */
+ MAX_STATE = 2;
+
+ for (var event of ["online", "offline"]) {
+ window["bodyOn" + event] = makeBodyHandler(event);
+
+ window.addEventListener(
+ event,
+ makeHandler("window.addEventListener('%1', ..., false)",
+ event, [2]));
+ }
+
+ doTest();
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug336682_2.xhtml b/dom/events/test/test_bug336682_2.xhtml
new file mode 100644
index 0000000000..d8012a15e1
--- /dev/null
+++ b/dom/events/test/test_bug336682_2.xhtml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+Bug 336682: online/offline events tests.
+
+Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/licenses/publicdomain/
+-->
+<window title="Mozilla Bug 336682"
+ onoffline="trace('lt;body onoffline=...'); windowOnoffline(this, event)"
+ ononline="trace('lt;body ononline=...'); windowOnonline(this, event)"
+
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=336682">
+Mozilla Bug 336682 (online/offline events)</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+</body>
+
+<script type="text/javascript" src="test_bug336682.js"/>
+<script class="testbody" type="text/javascript">
+<![CDATA[
+addLoadEvent(function() {
+ /** @see test_bug336682.js */
+ MAX_STATE = 2;
+
+ function makeWindowHandler(eventName) {
+ return function (aThis, aEvent) {
+ var handler = makeHandler("<body on%1='...'>", eventName, [1]);
+ handler(aEvent);
+ }
+ }
+
+ for (var event of ["online", "offline"]) {
+ window["windowOn" + event] = makeWindowHandler(event);
+
+ window.addEventListener(
+ event,
+ makeHandler("window.addEventListener('%1', ..., false)",
+ event, [2]),
+ false);
+ }
+
+ doTest();
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+]]>
+</script>
+
+</window>
diff --git a/dom/events/test/test_bug367781.html b/dom/events/test/test_bug367781.html
new file mode 100644
index 0000000000..30f5592498
--- /dev/null
+++ b/dom/events/test/test_bug367781.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=367781
+-->
+<head>
+ <title>Test for Bug 367781</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=367781">Mozilla Bug 367781</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug **/
+var eventCounter = 0;
+
+function handler(e) {
+ if (e.type == "DOMNodeInserted") {
+ ++eventCounter;
+ }
+}
+
+function doTest() {
+ var i1 = document.getElementById('i1');
+ var i2 = document.getElementById('i2');
+ var pre = i1.contentDocument.getElementsByTagName("pre")[0];
+ pre.addEventListener("DOMNodeInserted", handler);
+ pre.textContent = pre.textContent + pre.textContent;
+ ok(eventCounter == 1, "DOMNodeInserted should have been dispatched");
+
+ pre.remove();
+ i2.contentDocument.adoptNode(pre);
+ i2.contentDocument.body.appendChild(pre);
+ ok(eventCounter == 2, "DOMNodeInserted should have been dispatched in the new document");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+addLoadEvent(SimpleTest.finish);
+
+</script>
+</pre>
+<iframe id="i1" srcdoc="&lt;html&gt;&lt;body&gt;&lt;pre&gt;Foobar&lt;/pre&gt;&lt;/body&gt;&lt;/html&gt;"></iframe>
+<iframe id="i2" srcdoc="&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;"></iframe>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug379120.html b/dom/events/test/test_bug379120.html
new file mode 100644
index 0000000000..6df6b2c639
--- /dev/null
+++ b/dom/events/test/test_bug379120.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=379120
+-->
+<head>
+ <title>Test for Bug 379120</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=379120">Mozilla Bug 379120</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 379120 **/
+
+ var originalString = "<test></test>";
+
+ // Parse the content into an XMLDocument
+ var parser = new DOMParser();
+ var originalDoc = parser.parseFromString(originalString, "text/xml");
+
+ var stylesheetText =
+ "<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' " +
+ "version='1.0' xmlns='http://www.w3.org/1999/xhtml'> " +
+
+ "<xsl:output method='xml' version='1.0' encoding='UTF-8' " +
+ "doctype-system='http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' " +
+ "doctype-public='-//W3C//DTD XHTML 1.0 Transitional//EN' /> " +
+
+ "<xsl:template match='/'>" +
+ "<div onload='var i = 1'/>" +
+ "<xsl:apply-templates />" +
+ "</xsl:template>" +
+ "</xsl:stylesheet>";
+ var stylesheet = parser.parseFromString(stylesheetText, "text/xml");
+
+ var processor = new XSLTProcessor();
+
+ var targetDocument;
+ processor.importStylesheet (stylesheet);
+ var transformedDocument = processor.transformToDocument (originalDoc);
+ is(transformedDocument.documentElement.getAttribute("onload"),
+ "var i = 1");
+ is(transformedDocument.documentElement.onload, null, "Shouldn't have onload handler");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug402089.html b/dom/events/test/test_bug402089.html
new file mode 100644
index 0000000000..905a47a5c4
--- /dev/null
+++ b/dom/events/test/test_bug402089.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=402089
+-->
+<head>
+ <title>Test for Bug 402089</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<!-- setTimeout so that the test starts after paint suppression ends -->
+<body onload="setTimeout(doTest,0);">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=402089">Mozilla Bug 402089</a>
+<p id="display"></p>
+<div id="content">
+ <pre id="result1"></pre>
+ <pre id="result2"></pre>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 402089 **/
+
+var cachedEvent = null;
+
+function testCachedEvent() {
+ testEvent('result2');
+ ok((document.getElementById('result1').textContent ==
+ document.getElementById('result2').textContent),
+ "Event coordinates should be the same after dispatching.");
+ SimpleTest.finish();
+}
+
+function testEvent(res) {
+ var s = cachedEvent.type + "\n";
+ s += "clientX: " + cachedEvent.clientX + ", clientY: " + cachedEvent.clientY + "\n";
+ s += "screenX: " + cachedEvent.screenX + ", screenY: " + cachedEvent.screenY + "\n";
+ s += "layerX: " + cachedEvent.layerX + ", layerY: " + cachedEvent.layerY + "\n";
+ s += "pageX: " + cachedEvent.pageX + ", pageY: " + cachedEvent.pageY + "\n";
+ document.getElementById(res).textContent += s;
+}
+
+function clickHandler(e) {
+ cachedEvent = e;
+ testEvent('result1');
+ e.stopPropagation();
+ e.preventDefault();
+ window.removeEventListener("click", clickHandler, true);
+ setTimeout(testCachedEvent, 10);
+}
+
+function doTest() {
+ window.addEventListener("click", clickHandler, true);
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
+ utils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
+
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug405632.html b/dom/events/test/test_bug405632.html
new file mode 100644
index 0000000000..5eae056307
--- /dev/null
+++ b/dom/events/test/test_bug405632.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=405632
+-->
+<head>
+ <title>Test for Bug 405632</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=405632">Mozilla Bug 405632</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 405632 **/
+
+ var me = document.createEvent("mouseevent");
+ me.initMouseEvent("foo", false, false, window, 0, 100, 100, 100, 100,
+ false, false, false, false, 0, null);
+ ok(me.clientX == me.pageX,
+ "mouseEvent.clientX should be the same as mouseEvent.pageX when event is initialized manually");
+ ok(me.clientY == me.pageY,
+ "mouseEvent.clientY should be the same as mouseEvent.pageY when event is initialized manually");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug409604.html b/dom/events/test/test_bug409604.html
new file mode 100644
index 0000000000..9cfd93326d
--- /dev/null
+++ b/dom/events/test/test_bug409604.html
@@ -0,0 +1,379 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=409604
+-->
+<head>
+ <title>Test for Bug 409604</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body id="body">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=409604">Mozilla Bug 409604</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ /** Test for Bug 409604 **/
+
+ var expectedFocus = "a,c,d,e,f,g,h,i,j,k,l,m,n,p,x,y";
+ // XXX the "map" test is causing trouble, see bug 433089
+ var focusArray = expectedFocus.split(",");
+ var unfocusableElementId = "invalid";
+ var unfocusableTags = [
+ {tag: "abbr", content: "text", attribs: {title: "something"}},
+ {tag: "acronym", content: "text", attribs: {title: "something"}},
+ {tag: "address", content: "text"},
+ {tag: "b", content: "text"},
+ {tag: "bdo", content: "text"},
+ {tag: "big", content: "text"},
+ {tag: "blockquote", content: "text"},
+ {tag: "caption", content: "text", parent: "table", where: "first"},
+ {tag: "cite", content: "text"},
+ {tag: "code", content: "text"},
+ {tag: "dd", content: "text", parent: "dl"},
+ {tag: "del", content: "text"},
+ {tag: "dfn", content: "text", attribs: {title: "something"}},
+ {tag: "div", content: "text"},
+ {tag: "dl", content: "<dd>text</dd>", parent: "dl"},
+ {tag: "dt", content: "text", parent: "dl"},
+ {tag: "em", content: "text"},
+ {tag: "fieldset", content: "text"},
+ {tag: "form", content: "text", attribs: {action: "any.html"}},
+ {tag: "h1", content: "text"},
+ {tag: "h2", content: "text"},
+ {tag: "h3", content: "text"},
+ {tag: "h4", content: "text"},
+ {tag: "h5", content: "text"},
+ {tag: "h6", content: "text"},
+ {tag: "hr"},
+ {tag: "i", content: "text"},
+ {tag: "img", attribs: {src: "any.png", alt: "image"}},
+ {tag: "ins", content: "text"},
+ {tag: "kbd", content: "text"},
+ {tag: "li", content: "text", parent: "ol"},
+ {tag: "li", content: "text", parent: "ul"},
+ {tag: "noscript", content: "text"},
+ {tag: "ol", content: "<li>text</li>"},
+ {tag: "optgroup", content: "<option>text</option>", attribs: {label: "some label"}, parent: "select"},
+ {tag: "option", content: "text", parent: "select"},
+ {tag: "p", content: "text"},
+ {tag: "pre", content: "text"},
+ {tag: "q", content: "text"},
+ {tag: "samp", content: "text"},
+ {tag: "small", content: "text"},
+ {tag: "span", content: "text"},
+ {tag: "strong", content: "text"},
+ {tag: "sub", content: "text"},
+ {tag: "sup", content: "text"},
+ {tag: "tt", content: "text"},
+ {tag: "ul", content: "<li>text</li>"},
+ {tag: "var", content: "text"}
+ ];
+ var invalidElements = [
+ "body",
+ "col",
+ "colgroup",
+// XXX the "map" test is causing trouble, see bug 433089
+// "map",
+ "table",
+ "tbody",
+ "td",
+ "tfoot",
+ "th",
+ "thead",
+ "tr"
+ ];
+
+ function handleFocus(e) {
+ ok("accessKey" in e, "(focus) accesskey property not found on element");
+ var expected = focusArray.shift();
+ // "k" and "n" are a special cases because the element receiving the focus
+ // is not the element which has the accesskey.
+ if (expected == "k" || expected == "n") {
+ ok(e.value == "test for label", "(focus) unexpected element: " + e.value +
+ " expected: " + "test for label");
+ // "l" is a special case because the element receiving the focus is not
+ // the element which has the accesskey.
+ } else if (expected == "l") {
+ ok(e.value == "test for legend", "(focus) unexpected element: " + e.value +
+ " expected: " + "test for legend");
+ } else {
+ ok(expected == e.accessKey, "(focus) unexpected element: " + e.accessKey +
+ " expected: " + expected);
+ }
+ }
+
+ function handleClick(e) {
+ ok("accessKey" in e, "(click) accesskey property not found on element");
+ }
+
+ function handleInvalid(e) {
+ ok("accessKey" in e, "(invalid) accesskey property not found on element");
+ ok(false, "(invalid) accesskey should not have any effect on this element: " +
+ e.localName);
+ }
+
+ function pressAccessKey(key) {
+ synthesizeKey(key.key, {altKey: true, shiftKey: true});
+ }
+
+ function testFocusableElements() {
+ for (var code = "a".charCodeAt(0); code <= "y".charCodeAt(0); ++ code) {
+ // XXX the "map" test is causing trouble, see bug 433089
+ if (code == "b".charCodeAt(0))
+ continue;
+ var accessChar = String.fromCharCode(code).toUpperCase();
+ pressAccessKey({key: accessChar});
+ }
+ ok(focusArray.length == 0, "(focus) unhandled elements remaining: " + focusArray.join(","));
+ }
+
+ function createUnfocusableElement(elem, accesskey) {
+ ok("tag" in elem, "invalid object passed to createUnfocusableElement: " + elem.toString());
+ var e = document.createElement(elem.tag);
+ if ("content" in elem) {
+ e.innerHTML = elem.content;
+ }
+ if ("attribs" in elem) {
+ for (var attr in elem.attribs) {
+ e.setAttribute(attr, elem.attribs[attr]);
+ }
+ }
+ e.setAttribute("accesskey", accesskey);
+ e.setAttribute("onclick", "handleClick(event.target); event.preventDefault();");
+ e.setAttribute("onfocus", "handleInvalid(event.target);");
+ var parent = null;
+ var elementToInsert = null;
+ if ("parent" in elem) {
+ parent = document.getElementById(elem.parent);
+ elementToInsert = e;
+ } else {
+ parent = document.getElementById("tbody");
+ elementToInsert = document.createElement("tr");
+ var td = document.createElement("td");
+ td.textContent = elem.tag;
+ elementToInsert.appendChild(td);
+ td = document.createElement("td");
+ td.appendChild(e);
+ elementToInsert.appendChild(td);
+ }
+ ok(parent != null, "parent element not specified for element: " + elem.tag);
+ ok(elementToInsert != null, "elementToInsert not specified for element: " + elem.tag);
+ elementToInsert.setAttribute("id", unfocusableElementId);
+ if ("where" in elem) {
+ if (elem.where == "first") {
+ parent.insertBefore(elementToInsert, parent.firstChild);
+ } else {
+ ok(false, "invalid where value specified for element: " + elem.tag);
+ }
+ } else {
+ parent.appendChild(elementToInsert);
+ }
+ }
+
+ function destroyUnfocusableElement() {
+ var el = document.getElementById(unfocusableElementId);
+ ok(el != null, "unfocusable element not found");
+ el.remove();
+ ok(document.getElementById(unfocusableElementId) == null, "unfocusable element not properly removed");
+ }
+
+ function testUnfocusableElements() {
+ var i, e;
+ for (i = 0; i < unfocusableTags.length; ++ i) {
+ createUnfocusableElement(unfocusableTags[i], "z");
+ pressAccessKey({key: "Z"});
+ destroyUnfocusableElement();
+ }
+ for (i = 0; i < invalidElements.length; ++ i) {
+ e = document.getElementById(invalidElements[i]);
+ ok(e != null, "element with ID " + invalidElements[i] + " not found");
+ e.setAttribute("accesskey", "z");
+ e.setAttribute("onclick", "handleClick(event.target); event.preventDefault();");
+ e.setAttribute("onfocus", "handleInvalid(event.target);");
+ pressAccessKey({key: "Z"});
+ e.removeAttribute("accesskey");
+ e.removeAttribute("onclick");
+ e.removeAttribute("onfocus");
+ }
+ }
+
+ function start() {
+ testFocusableElements();
+ testUnfocusableElements();
+ SimpleTest.finish();
+ }
+
+ function doTest() {
+ SpecialPowers.pushPrefEnv({"set": [["ui.key.contentAccess", 5]]}, start);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+
+</script>
+</pre>
+ <table id="table">
+ <thead id="thead">
+ <tr id="tr"><th id="th">Test header</th><th></th></tr>
+ </thead>
+ <tfoot id="tfoot">
+ <tr><td id="td">Test footer</td><td></td></tr>
+ </tfoot>
+ <tbody id="tbody">
+ <colgroup id="colgroup">
+ <col id="col"></col>
+ <col></col>
+ </colgroup>
+ <tr>
+ <td>a</td><td><a href="#" onclick="handleClick(event.target); return false;" accesskey="a" onfocus="handleFocus(event.target);">test link"</a></td>
+ </tr>
+<!-- the "map" test is causing trouble, see bug 433089
+ <tr>
+ <td>area</td><td><img src="about:logo" width="300" height="236" usemap="#map">
+ <map id="map" name="map"><area shape="rect" coords="0,0,82,126" href="#"
+ onclick="handleClick(event.target); return false;" accesskey="b"></map>
+ </td>
+ </tr>
+-->
+ <tr>
+ <td>button</td><td><button onclick="handleClick(event.target);" accesskey="c" onfocus="handleFocus(event.target);">test button"</button></td>
+ </tr>
+ <tr>
+ <td>input type="text"</td><td><input type="text" value="" onclick="handleClick(event.target);" onfocus="handleFocus(event.target);" accesskey="d"></td>
+ </tr>
+ <tr>
+ <td>input type="button"</td><td><input type="button" value="type='button'" onclick="handleClick(event.target);" onfocus="handleFocus(event.target);" accesskey="e"></td>
+ </tr>
+ <tr>
+ <td>input type="checkbox"</td><td><input type="checkbox" onclick="handleClick(event.target);" onfocus="handleFocus(event.target)" accesskey="f"></td>
+ </tr>
+ <tr>
+ <td>input type="radio"</td><td><input type="radio" name="radio" onclick="handleClick(event.target);" onfocus="handleFocus(event.target);" accesskey="g"></td>
+ </tr>
+ <tr>
+ <td>input type="password"</td><td><input type="password" onclick="handleClick(event.target);" onfocus="handleFocus(event.target);" accesskey="h"></td>
+ </tr>
+ <tr>
+ <td>input type="submit"</td><td><input type="submit" value="type='submit'" onclick="handleClick(event.target); return false;"
+ onfocus="handleFocus(event.target);" accesskey="i"></td>
+ </tr>
+ <tr>
+ <td>input type="reset"</td><td><input type="submit" value="type='reset'" onclick="handleClick(event.target);"
+ onfocus="handleFocus(event.target);" accesskey="j"></td>
+ </tr>
+ <tr>
+ <td>label</td><td><label accesskey="k" onclick="handleClick(event.target);" onfocus="handleInvalid(event.target);">test label
+ <input type="text" value="test for label" onfocus="handleFocus(event.target);" onclick="handleClick(event.target);"></label></td>
+ </tr>
+ <tr>
+ <td>legend</td><td><fieldset><legend accesskey="l">test legend</legend>
+ <input type="text" value="test for legend" onfocus="handleFocus(event.target);" onclick="handleClick(event.target);" ></fieldset></td>
+ </tr>
+ <tr>
+ <td>textarea</td><td><textarea onfocus="handleFocus(event.target);" onclick="handleClick(event.target);" accesskey="m">test text</textarea></td>
+ </tr>
+ <tr>
+ <td>label (label invisible)</td><td><label for="txt1" accesskey="n" style="display:none"
+ onclick="handleClick(event.target);" onfocus="handleInvalid(event.target);">test label</label>
+ <input type="text" id="txt1" value="test for label" onclick="handleClick(event.target);" onfocus="handleFocus(event.target);"></td>
+ </tr>
+ <tr>
+ <td>label (control invisible)</td><td><label for="txt2" accesskey="o"
+ onclick="handleClick(event.target);" onfocus="handleInvalid(event.target);">test label</label>
+ <input type="text" id="txt2" value="test for label" onclick="handleClick(event.target);"
+ onfocus="handleInvalid(event.target);" style="display:none"></td>
+ </tr>
+ <tr>
+ <td>select</td>
+ <td>
+ <select onclick="handleClick(event.target);" onfocus="handleFocus(event.target)" accesskey="p"><option>option</option></select>
+ </td>
+ </tr>
+ <tr>
+ <td>object</td>
+ <td>
+ <object onclick="handleClick(event.target);" onfocus="handleInvalid(event.target)" accesskey="q">an object</object>
+ </td>
+ </tr>
+ <tr>
+ <td>a without href</td>
+ <td>
+ <a onclick="handleClick(event.target);" onfocus="handleInvalid(event.target)" accesskey="r">an object</object>
+ </td>
+ </tr>
+ <tr>
+ <td>disabled button</td>
+ <td>
+ <button disabled="" onclick="handleClick(event.target);" onfocus="handleInvalid(event.target)" accesskey="s">disabled</button>
+ </td>
+ </tr>
+ <tr>
+ <td>disabled input</td>
+ <td>
+ <input disabled="" onclick="handleClick(event.target);" onfocus="handleInvalid(event.target)" accesskey="t"></input>
+ </td>
+ </tr>
+ <tr>
+ <td>hidden input</td>
+ <td>
+ <input type="hidden" onclick="handleClick(event.target);" onfocus="handleInvalid(event.target)" accesskey="u">disabled</input>
+ </td>
+ </tr>
+ <tr>
+ <td>disabled select</td>
+ <td>
+ <select disabled onclick="handleClick(event.target);" onfocus="handleInvalid(event.target)" accesskey="v">
+ <option>disabled</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>disabled textarea</td>
+ <td>
+ <textarea disabled onclick="handleClick(event.target);" onfocus="handleInvalid(event.target)" accesskey="w">disabled</textarea>
+ </td>
+ </tr>
+ <tr>
+ <td>scrollable div(focusable)</td>
+ <td>
+ <div onclick="handleClick(event.target);" onfocus="handleFocus(event.target)" accesskey="x" style="height: 50px; overflow: auto;">
+ The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy
+
+ dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the
+
+ lazy dog. The quick brown fox jumps over the lazy dog.
+ The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy
+
+ dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the
+
+ lazy dog. The quick brown fox jumps over the lazy dog.
+ The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy
+
+ dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the
+
+ lazy dog. The quick brown fox jumps over the lazy dog.
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>contenteditable div(focusable)</td>
+ <td>
+ <div onclick="handleClick(event.target);" onfocus="handleFocus(event.target)" accesskey="y" contenteditable="true">
+ Test text.....
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <dl id="dl"></dl>
+ <ul id="ul"></ul>
+ <ol id="ol"></ol>
+ <select id="select"></select>
+</body>
+</html>
diff --git a/dom/events/test/test_bug412567.html b/dom/events/test/test_bug412567.html
new file mode 100644
index 0000000000..86f7001fc2
--- /dev/null
+++ b/dom/events/test/test_bug412567.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=412567
+-->
+<head>
+ <title>Test for Bug 412567</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="testRedispatching(event);">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=412567">Mozilla Bug 412567</a>
+<p id="display"></p>
+<div id="content" style="display: none" onload="redispatchinHandler(event)">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 412567 **/
+
+var loadEvent = null;
+
+function redispatchinHandler(evt) {
+ is(evt.type, "load", "Wrong event type!");
+ ok(!evt.isTrusted, "Event should not be trusted!");
+ SimpleTest.finish();
+}
+
+function redispatch() {
+ ok(loadEvent.isTrusted, "Event should be trusted before redispatching!");
+ document.getElementById('content').dispatchEvent(loadEvent);
+}
+
+function testRedispatching(evt) {
+ is(evt.type, "load", "Wrong event type!");
+ ok(evt.isTrusted, "Event should be trusted!");
+ loadEvent = evt;
+ setTimeout(redispatch, 0);
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug415498.xhtml b/dom/events/test/test_bug415498.xhtml
new file mode 100644
index 0000000000..c726141bf7
--- /dev/null
+++ b/dom/events/test/test_bug415498.xhtml
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=415498
+-->
+<window title="Mozilla Bug 415498"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="init()">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/chrome-harness.js"></script>
+<body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=415498">Mozilla Bug 415498</a>
+
+ <p id="display"></p>
+
+ <pre id="test">
+ <script class="testbody" type="application/javascript"><![CDATA[
+ const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
+
+ /** Test for Bug 415498 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var gTestsIterator;
+ var gConsole;
+ var gConsoleListener;
+ var gMessages = [];
+
+ function init() {
+ gTestsIterator = testsIterator();
+
+ gConsole = Cc["@mozilla.org/consoleservice;1"].
+ getService(Ci.nsIConsoleService);
+
+ gConsoleListener = {
+ observe: function(aObject) {
+ gMessages.push(aObject);
+ }
+ };
+ gConsole.registerListener(gConsoleListener);
+
+ nextTest();
+ }
+
+ function nextTest() {
+ let {done} = gTestsIterator.next();
+ if (done) {
+ if (gConsole && gConsoleListener) {
+ gConsole.unregisterListener(gConsoleListener);
+ }
+ SimpleTest.finish();
+ }
+ }
+
+ function* testsIterator() {
+
+ var browser = $("browser");
+ browser.addEventListener("load", function() {
+ setTimeout(nextTest, 0)
+ }, false);
+
+ // 1) This document uses addEventListener to register a method throwing an exception
+ var chromeDir = getRootDirectory(window.location.href);
+ BrowserTestUtils.loadURI(browser, chromeDir + "bug415498-doc1.html");
+ yield undefined;
+
+ ok(verifyErrorReceived("HierarchyRequestError"),
+ "Error message not reported in event listener callback!");
+ gMessages = [];
+
+ // 2) This document sets window.onload to register a method throwing an exception
+ var chromeDir = getRootDirectory(window.location.href);
+ BrowserTestUtils.loadURI(browser, chromeDir + "bug415498-doc2.html");
+ yield undefined;
+
+ ok(verifyErrorReceived("HierarchyRequestError"),
+ "Error message not reported in window.onload!");
+ }
+
+ function verifyErrorReceived(errorString) {
+ for (var i = 0; i < gMessages.length; i++) {
+ if (gMessages[i].message.includes(errorString))
+ return true;
+ }
+ return false;
+ }
+ ]]></script>
+ </pre>
+</body>
+
+<browser id="browser" type="content" flex="1" src="about:blank"/>
+
+</window>
diff --git a/dom/events/test/test_bug418986-3.html b/dom/events/test/test_bug418986-3.html
new file mode 100644
index 0000000000..3ede005902
--- /dev/null
+++ b/dom/events/test/test_bug418986-3.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=418986
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test 3/3 for Bug 418986 - Resist fingerprinting by preventing exposure of screen and system info</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body id="body">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a>
+<p id="display"></p>
+<pre id="test"></pre>
+<script type="application/javascript" src="bug418986-3.js"></script>
+<script type="application/javascript">
+ // This test produces fake mouse events and checks that the screenX and screenY
+ // properties of the received event objects provide client window coordinates.
+ // Run the test once the window has loaded.
+ window.onload = () => test(true);
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug418986-3.xhtml b/dom/events/test/test_bug418986-3.xhtml
new file mode 100644
index 0000000000..426d888998
--- /dev/null
+++ b/dom/events/test/test_bug418986-3.xhtml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+Bug 418986
+-->
+<window title="Mozilla Bug 418986"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<body id="body" xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">
+Mozilla Bug 418986</a>
+</body>
+
+<script type="application/javascript" src="bug418986-3.js"></script>
+<script type="application/javascript"><![CDATA[
+ // This test produces fake mouse events and checks that the screenX and screenY
+ // properties of the received event objects provide client window coordinates.
+ // Run the test once the window has loaded.
+ test(false);
+]]></script>
+
+</window>
diff --git a/dom/events/test/test_bug422132.html b/dom/events/test/test_bug422132.html
new file mode 100644
index 0000000000..0375104f54
--- /dev/null
+++ b/dom/events/test/test_bug422132.html
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=422132
+-->
+<head>
+ <title>Test for Bug 422132</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=422132">Mozilla Bug 422132</a>
+<p id="display"></p>
+<div id="target" style="font-size: 0; width: 200px; height: 200px; overflow: auto;">
+ <div style="width: 1000px; height: 1000px;"></div>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 422132 **/
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+ SpecialPowers.pushPrefEnv({
+ "set":[["general.smoothScroll", false],
+ ["mousewheel.min_line_scroll_amount", 1],
+ ["mousewheel.system_scroll_override_on_root_content.enabled", false],
+ ["mousewheel.transaction.timeout", 100000]]}, runTests)}, window);
+
+function runTests()
+{
+ var target = document.getElementById("target");
+
+ var scrollLeft = target.scrollLeft;
+ var scrollTop = target.scrollTop;
+
+ var tests = [
+ {
+ prepare() {
+ scrollLeft = target.scrollLeft;
+ scrollTop = target.scrollTop;
+ },
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.5,
+ deltaY: 0.5,
+ lineOrPageDeltaX: 0,
+ lineOrPageDeltaY: 0
+ },
+ }, {
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.5,
+ deltaY: 0.5,
+ lineOrPageDeltaX: 0,
+ lineOrPageDeltaY: 0
+ },
+ check() {
+ is(target.scrollLeft - scrollLeft, 1,
+ "not scrolled to right by 0.5px delta value with pending 0.5px delta");
+ is(target.scrollTop - scrollTop, 1,
+ "not scrolled to bottom by 0.5px delta value with pending 0.5px delta");
+ },
+ }, {
+ prepare() {
+ scrollLeft = target.scrollLeft;
+ scrollTop = target.scrollTop;
+ },
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5,
+ deltaY: 0.5,
+ lineOrPageDeltaX: 0,
+ lineOrPageDeltaY: 0
+ },
+ }, {
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5,
+ deltaY: 0.5,
+ lineOrPageDeltaX: 1,
+ lineOrPageDeltaY: 1
+ },
+ check() {
+ is(target.scrollLeft - scrollLeft, 1,
+ "not scrolled to right by 0.5 line delta value with pending 0.5 line delta");
+ is(target.scrollTop - scrollTop, 1,
+ "not scrolled to bottom by 0.5 line delta value with pending 0.5 line delta");
+ }
+ }
+ ];
+
+ var nextTest = function() {
+ var test = tests.shift();
+ if (test.prepare) {
+ test.prepare();
+ }
+
+ sendWheelAndPaint(target, 10, 10, test.event, function() {
+ if (test.check) {
+ test.check();
+ }
+ if (tests.length == 0) {
+ SimpleTest.finish();
+ return;
+ }
+
+ setTimeout(nextTest, 0);
+ });
+ }
+
+ nextTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug426082.html b/dom/events/test/test_bug426082.html
new file mode 100644
index 0000000000..1f68ea867f
--- /dev/null
+++ b/dom/events/test/test_bug426082.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=426082
+-->
+<head>
+ <title>Test for Bug 426082</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 426082 **/
+SimpleTest.waitForExplicitFinish();
+var subwindow = window.open("./bug426082.html", "bug426082", "width=800,height=1000");
+
+function finishTests() {
+ subwindow.close();
+ SimpleTest.finish();
+}
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug427537.html b/dom/events/test/test_bug427537.html
new file mode 100644
index 0000000000..f3d0641a97
--- /dev/null
+++ b/dom/events/test/test_bug427537.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=427537
+-->
+<head>
+ <title>Test for Bug 427537</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=427537">Mozilla Bug 427537</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 427537 **/
+
+var e = document.createEvent("CustomEvent");
+ok(e, "Should have custom event!");
+
+// Test initCustomEvent and also cycle collection handling by
+// passing reference to the event as 'detail' parameter.
+e.initCustomEvent("foobar", true, true, e);
+
+var didCallListener = false;
+document.addEventListener("foobar",
+ function(evt) {
+ didCallListener = true;
+ is(evt.type, "foobar", "Should get 'foobar' event!");
+ is(evt.detail, evt, ".detail should point to the event itself.");
+ ok(e.bubbles, "Event should bubble!");
+ ok(e.cancelable, "Event should be cancelable.");
+ }, true);
+
+document.dispatchEvent(e);
+ok(didCallListener, "Should have called listener!");
+
+e = document.createEvent("CustomEvent");
+e.initEvent("foo", true, true);
+is(e.detail, null, "Default detail should be null.");
+
+e = document.createEvent("CustomEvent");
+e.initCustomEvent("foobar", true, true, 1);
+is(e.detail, 1, "Detail should be 1.");
+
+e = document.createEvent("CustomEvent");
+e.initCustomEvent("foobar", true, true, "test");
+is(e.detail, "test", "Detail should be 'test'.");
+
+e = document.createEvent("CustomEvent");
+e.initCustomEvent("foobar", true, true, true);
+is(e.detail, true, "Detail should be true.");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug428988.html b/dom/events/test/test_bug428988.html
new file mode 100644
index 0000000000..5caec887a0
--- /dev/null
+++ b/dom/events/test/test_bug428988.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=428988
+-->
+<head>
+ <title>Test for Bug 428988</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=428988">Mozilla Bug 428988</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 428988 **/
+
+function listenerForClick(evt) {
+ is(Math.round(evt.mozPressure*100), 56, "Wrong .mozPressure");
+}
+
+function doTest() {
+ var target = document.getElementById("testTarget");
+ target.addEventListener("click", listenerForClick, true);
+ var me = document.createEvent("MouseEvent");
+ me.initNSMouseEvent("click", true, true, window, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null, 0.56, 0);
+ target.dispatchEvent(me);
+ target.removeEventListener("click", listenerForClick, true);
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+</script>
+</pre>
+<span id="testTarget" style="border: 1px solid black;">testTarget</span>
+</body>
+</html>
diff --git a/dom/events/test/test_bug432698.html b/dom/events/test/test_bug432698.html
new file mode 100644
index 0000000000..8dec5c2cec
--- /dev/null
+++ b/dom/events/test/test_bug432698.html
@@ -0,0 +1,223 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=432698
+-->
+<head>
+ <title>Test for Bug 432698</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=432698">Mozilla Bug 432698</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 432698 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests);
+var outer;
+var middle;
+var inner;
+var outside;
+var container;
+var file;
+var iframe;
+var checkRelatedTarget = false;
+var expectedRelatedEnter = null;
+var expectedRelatedLeave = null;
+var mouseentercount = 0;
+var mouseleavecount = 0;
+var mouseovercount = 0;
+var mouseoutcount = 0;
+
+function sendMouseEvent(t, elem) {
+ var r = elem.getBoundingClientRect();
+ synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
+}
+
+var expectedMouseEnterTargets = [];
+var expectedMouseLeaveTargets = [];
+
+function runTests() {
+ outer = document.getElementById("outertest");
+ middle = document.getElementById("middletest");
+ inner = document.getElementById("innertest");
+ outside = document.getElementById("outside");
+ container = document.getElementById("container");
+ file = document.getElementById("file");
+ iframe = document.getElementById("iframe");
+
+ // Make sure ESM thinks mouse is outside the test elements.
+ sendMouseEvent("mousemove", outside);
+
+ mouseentercount = 0;
+ mouseleavecount = 0;
+ mouseovercount = 0;
+ mouseoutcount = 0;
+ checkRelatedTarget = true;
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = inner;
+ expectedMouseEnterTargets = ["outertest", "middletest", "innertest"];
+ sendMouseEvent("mousemove", inner);
+ is(mouseentercount, 3, "Unexpected mouseenter event count!");
+ is(mouseovercount, 1, "Unexpected mouseover event count!");
+ is(mouseoutcount, 0, "Unexpected mouseout event count!");
+ is(mouseleavecount, 0, "Unexpected mouseleave event count!");
+ expectedRelatedEnter = inner;
+ expectedRelatedLeave = outside;
+ expectedMouseLeaveTargets = ["innertest", "middletest", "outertest"];
+ sendMouseEvent("mousemove", outside);
+ is(mouseentercount, 3, "Unexpected mouseenter event count!");
+ is(mouseovercount, 1, "Unexpected mouseover event count!");
+ is(mouseoutcount, 1, "Unexpected mouseout event count!");
+ is(mouseleavecount, 3, "Unexpected mouseleave event count!");
+
+ // Event handling over native anonymous content.
+ var r = file.getBoundingClientRect();
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = file;
+ synthesizeMouse(file, r.width / 6, r.height / 2, {type: "mousemove"});
+ is(mouseentercount, 4, "Unexpected mouseenter event count!");
+ is(mouseovercount, 2, "Unexpected mouseover event count!");
+ is(mouseoutcount, 1, "Unexpected mouseout event count!");
+ is(mouseleavecount, 3, "Unexpected mouseleave event count!");
+
+ // Moving mouse over type="file" shouldn't cause mouseover/out/enter/leave events
+ synthesizeMouse(file, r.width - (r.width / 6), r.height / 2, {type: "mousemove"});
+ is(mouseentercount, 4, "Unexpected mouseenter event count!");
+ is(mouseovercount, 2, "Unexpected mouseover event count!");
+ is(mouseoutcount, 1, "Unexpected mouseout event count!");
+ is(mouseleavecount, 3, "Unexpected mouseleave event count!");
+
+ expectedRelatedEnter = file;
+ expectedRelatedLeave = outside;
+ sendMouseEvent("mousemove", outside);
+ is(mouseentercount, 4, "Unexpected mouseenter event count!");
+ is(mouseovercount, 2, "Unexpected mouseover event count!");
+ is(mouseoutcount, 2, "Unexpected mouseout event count!");
+ is(mouseleavecount, 4, "Unexpected mouseleave event count!");
+
+ // Initialize iframe
+ iframe.contentDocument.documentElement.style.overflow = "hidden";
+ iframe.contentDocument.body.style.margin = "0px";
+ iframe.contentDocument.body.style.width = "100%";
+ iframe.contentDocument.body.style.height = "100%";
+ iframe.contentDocument.body.innerHTML =
+ "<div style='width: 100%; height: 50%; border: 1px solid black;'></div>" +
+ "<div style='width: 100%; height: 50%; border: 1px solid black;'></div>";
+ iframe.contentDocument.body.offsetLeft; // flush
+
+ iframe.contentDocument.body.firstChild.onmouseenter = menter;
+ iframe.contentDocument.body.firstChild.onmouseleave = mleave;
+ iframe.contentDocument.body.lastChild.onmouseenter = menter;
+ iframe.contentDocument.body.lastChild.onmouseleave = mleave;
+ r = iframe.getBoundingClientRect();
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = iframe;
+ // Move mouse inside the iframe.
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height / 4, {type: "mousemove"},
+ iframe.contentWindow);
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height - (r.height / 4), {type: "mousemove"},
+ iframe.contentWindow);
+ is(mouseentercount, 7, "Unexpected mouseenter event count!");
+ expectedRelatedEnter = iframe;
+ expectedRelatedLeave = outside;
+ sendMouseEvent("mousemove", outside);
+ is(mouseleavecount, 7, "Unexpected mouseleave event count!");
+
+ checkRelatedTarget = false;
+
+ iframe.contentDocument.body.firstChild.onmouseenter = null;
+ iframe.contentDocument.body.firstChild.onmouseleave = null;
+ iframe.contentDocument.body.lastChild.onmouseenter = null;
+ iframe.contentDocument.body.lastChild.onmouseleave = null;
+
+ container.onmouseenter = null;
+ container.onmouseleave = null;
+ container.onmouseout = null;
+ container.onmouseover = null;
+
+ var children = container.getElementsByTagName('*');
+ for (var i=0;i<children.length;i++) {
+ children[i].onmouseenter = null;
+ children[i].onmouseleave = null;
+ children[i].onmouseout = null;
+ children[i].onmouseover = null;
+ }
+
+ SimpleTest.finish();
+}
+
+function menter(evt) {
+ ++mouseentercount;
+ evt.stopPropagation();
+ if (expectedMouseEnterTargets.length) {
+ var t = expectedMouseEnterTargets.shift();
+ is(evt.target.id, t, "Wrong event target!");
+ }
+ is(evt.bubbles, false, evt.type + " should not bubble!");
+ is(evt.cancelable, false, evt.type + " is not cancelable!");
+ is(evt.target, evt.currentTarget, "Wrong event target!");
+ ok(!evt.relatedTarget || evt.target.ownerDocument == evt.relatedTarget.ownerDocument,
+ "Leaking nodes to another document?");
+ if (checkRelatedTarget && evt.target.ownerDocument == document) {
+ is(evt.relatedTarget, expectedRelatedEnter, "Wrong related target (mouseenter)");
+ }
+}
+
+function mleave(evt) {
+ ++mouseleavecount;
+ evt.stopPropagation();
+ if (expectedMouseLeaveTargets.length) {
+ var t = expectedMouseLeaveTargets.shift();
+ is(evt.target.id, t, "Wrong event target!");
+ }
+ is(evt.bubbles, false, evt.type + " should not bubble!");
+ is(evt.cancelable, false, evt.type + " is not cancelable!");
+ is(evt.target, evt.currentTarget, "Wrong event target!");
+ ok(!evt.relatedTarget || evt.target.ownerDocument == evt.relatedTarget.ownerDocument,
+ "Leaking nodes to another document?");
+ if (checkRelatedTarget && evt.target.ownerDocument == document) {
+ is(evt.relatedTarget, expectedRelatedLeave, "Wrong related target (mouseleave)");
+ }
+}
+
+function mover(evt) {
+ ++mouseovercount;
+ evt.stopPropagation();
+}
+
+function mout(evt) {
+ ++mouseoutcount;
+ evt.stopPropagation();
+}
+
+</script>
+</pre>
+<div id="container" onmouseenter="menter(event)" onmouseleave="mleave(event)"
+ onmouseout="mout(event)" onmouseover="mover(event)">
+ <div id="outside" onmouseout="event.stopPropagation()" onmouseover="event.stopPropagation()">foo</div>
+ <div id="outertest" onmouseenter="menter(event)" onmouseleave="mleave(event)"
+ onmouseout="mout(event)" onmouseover="mover(event)">
+ <div id="middletest" onmouseenter="menter(event)" onmouseleave="mleave(event)"
+ onmouseout="mout(event)" onmouseover="mover(event)">
+ <div id="innertest" onmouseenter="menter(event)" onmouseleave="mleave(event)"
+ onmouseout="mout(event)" onmouseover="mover(event)">foo</div>
+ </div>
+ </div>
+ <input type="file" id="file"
+ onmouseenter="menter(event)" onmouseleave="mleave(event)"
+ onmouseout="mout(event)" onmouseover="mover(event)">
+ <br>
+ <iframe id="iframe" width="50px" height="50px"
+ onmouseenter="menter(event)" onmouseleave="mleave(event)"
+ onmouseout="mout(event)" onmouseover="mover(event)"></iframe>
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug443985.html b/dom/events/test/test_bug443985.html
new file mode 100644
index 0000000000..01180be00e
--- /dev/null
+++ b/dom/events/test/test_bug443985.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=443985
+-->
+<head>
+ <title>Test for Bug 443985</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=443985">Mozilla Bug 443985</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 443985 **/
+
+
+function listenerForNoScroll(evt) {
+ is(evt.clientX, evt.pageX, "Wrong .pageX");
+ is(evt.clientY, evt.pageY, "Wrong .pageY");
+ is(evt.screenX, 0, "Wrong .screenX");
+ is(evt.screenY, 0, "Wrong .screenY");
+ is(evt.clientX, 10, "Wrong .clientX");
+ is(evt.clientY, 10, "Wrong .clientY");
+}
+
+function listenerForScroll(evt) {
+ isnot(evt.clientX, evt.pageX, "Wrong .pageX");
+ isnot(evt.clientY, evt.pageY, "Wrong .pageY");
+ ok(evt.pageX > 3000, "Wrong .pageX");
+ ok(evt.pageY > 3000, "Wrong .pageY");
+ is(evt.screenX, 0, "Wrong .screenX");
+ is(evt.screenY, 0, "Wrong .screenY");
+ is(evt.clientX, 10, "Wrong .clientX");
+ is(evt.clientY, 10, "Wrong .clientY");
+}
+
+function doTest() {
+ window.scrollTo(0, 0);
+ var target = document.getElementById("testTarget");
+ target.addEventListener("click", listenerForNoScroll, true);
+ var me = document.createEvent("MouseEvent");
+ me.initMouseEvent("click", true, true, window, 0, 0, 0, 10, 10,
+ false, false, false, false, 0, null);
+ target.dispatchEvent(me);
+ target.removeEventListener("click", listenerForNoScroll, true);
+
+ target.scrollIntoView(true);
+ target.addEventListener("click", listenerForScroll, true);
+ me = document.createEvent("MouseEvent");
+ me.initMouseEvent("click", true, true, window, 0, 0, 0, 10, 10,
+ false, false, false, false, 0, null);
+ target.dispatchEvent(me);
+ target.addEventListener("click", listenerForNoScroll, true);
+
+ document.getElementsByTagName("a")[0].scrollIntoView(true);
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+</script>
+</pre>
+<div style="min-height: 4000px; min-width: 4000px;"></div>
+<div style="min-width: 4000px; text-align: right;">
+ <span id="testTarget" style="border: 1px solid black;">testTarget</span>
+</div>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug447736.html b/dom/events/test/test_bug447736.html
new file mode 100644
index 0000000000..0e6bca10e3
--- /dev/null
+++ b/dom/events/test/test_bug447736.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=447736
+-->
+<head>
+ <title>Test for Bug 447736</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=447736">Mozilla Bug 447736</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="secondTarget"></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 447736 **/
+
+var loadEvent = null;
+window.addEventListener("load",
+ function (evt) {
+ is(evt.target, window.document, "Wrong target!");
+ is(evt.originalTarget, window.document, "Wrong originalTarget!");
+ ok(evt.isTrusted, "Event should be trusted!");
+ loadEvent = evt;
+ setTimeout("st.dispatchEvent(loadEvent)", 0);
+ }, true);
+
+var st = document.getElementById("secondTarget");
+st.addEventListener("load",
+ function (evt) {
+ is(evt.target, st, "Wrong target! (2)");
+ is(evt.originalTarget, st, "Wrong originalTarget! (2)");
+ ok(!evt.isTrusted, "Event shouldn't be trusted anymore!");
+ SimpleTest.finish();
+ }, true);
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug448602.html b/dom/events/test/test_bug448602.html
new file mode 100644
index 0000000000..c4c8b42ce2
--- /dev/null
+++ b/dom/events/test/test_bug448602.html
@@ -0,0 +1,220 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=448602
+-->
+<head>
+ <title>Test for Bug 448602</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448602">Mozilla Bug 448602</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 448602 **/
+
+var els, root, l2, l3;
+
+function runTests() {
+ els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
+ .getService(SpecialPowers.Ci.nsIEventListenerService);
+
+ // Event listener info tests
+ root = document.getElementById("testroot");
+ var infos = els.getListenerInfoFor(root);
+ is(infos.length, 0, "Element shouldn't have listeners (1)");
+
+ var listenerSource = 'alert(event);';
+ root.setAttribute("onclick", listenerSource);
+ infos = els.getListenerInfoFor(root);
+ is(infos.length, 1, "Element should have listeners (1)");
+ is(infos[0].toSource(), 'function onclick(event) {\n' + listenerSource + '\n}',
+ "Unexpected serialization (1)");
+ is(infos[0].type, "click", "Wrong type (1)");
+ is(infos[0].capturing, false, "Wrong phase (1)");
+ is(infos[0].allowsUntrusted, true, "Should allow untrusted events (1)");
+ is(SpecialPowers.unwrap(infos[0].listenerObject), root.onclick,
+ "Should have the right listener object (1)");
+
+ root.removeAttribute("onclick");
+ root.setAttribute("onclick", "...invalid script...");
+ SimpleTest.expectUncaughtException(true);
+ infos = els.getListenerInfoFor(root);
+ SimpleTest.expectUncaughtException(false);
+ is(infos.length, 1);
+ is(infos[0].listenerObject, null);
+
+ root.removeAttribute("onclick");
+ infos = els.getListenerInfoFor(root);
+ is(infos.length, 0, "Element shouldn't have listeners (2)");
+
+ var l = function (e) { alert(e); };
+ root.addEventListener("foo", l, true, true);
+ root.addEventListener("foo", l, false, false);
+ infos = els.getListenerInfoFor(root);
+ is(infos.length, 2, "Element should have listeners (2)");
+ is(infos[0].toSource(), "(function (e) { alert(e); })",
+ "Unexpected serialization (2)");
+ is(infos[0].type, "foo", "Wrong type (2)");
+ is(infos[0].capturing, true, "Wrong phase (2)");
+ is(infos[0].allowsUntrusted, true, "Should allow untrusted events (2)");
+ is(SpecialPowers.unwrap(infos[0].listenerObject), l,
+ "Should have the right listener object (2)");
+ is(infos[1].toSource(), "(function (e) { alert(e); })",
+ "Unexpected serialization (3)");
+ is(infos[1].type, "foo", "Wrong type (3)");
+ is(infos[1].capturing, false, "Wrong phase (3)");
+ is(infos[1].allowsUntrusted, false, "Shouldn't allow untrusted events (1)");
+ is(SpecialPowers.unwrap(infos[1].listenerObject), l,
+ "Should have the right listener object (3)");
+
+ root.removeEventListener("foo", l, true);
+ root.removeEventListener("foo", l);
+ infos = els.getListenerInfoFor(root);
+ is(infos.length, 0, "Element shouldn't have listeners (3)");
+
+ root.onclick = l;
+ infos = els.getListenerInfoFor(root);
+ is(infos.length, 1, "Element should have listeners (3)");
+ is(infos[0].toSource(), '(function (e) { alert(e); })',
+ "Unexpected serialization (4)");
+ is(infos[0].type, "click", "Wrong type (4)");
+ is(infos[0].capturing, false, "Wrong phase (4)");
+ is(infos[0].allowsUntrusted, true, "Should allow untrusted events (3)");
+ is(SpecialPowers.unwrap(infos[0].listenerObject), l,
+ "Should have the right listener object (4)");
+
+ // Event target chain tests
+ l2 = document.getElementById("testlevel2");
+ l3 = document.getElementById("testlevel3");
+ var textnode = l3.firstChild;
+ var chain = els.getEventTargetChainFor(textnode, true);
+ ok(chain.length > 3, "Too short event target chain.");
+ ok(SpecialPowers.compare(chain[0], textnode), "Wrong chain item (1)");
+ ok(SpecialPowers.compare(chain[1], l3), "Wrong chain item (2)");
+ ok(SpecialPowers.compare(chain[2], l2), "Wrong chain item (3)");
+ ok(SpecialPowers.compare(chain[3], root), "Wrong chain item (4)");
+
+ var hasDocumentInChain = false;
+ var hasWindowInChain = false;
+ for (var i = 0; i < chain.length; ++i) {
+ if (SpecialPowers.compare(chain[i], document)) {
+ hasDocumentInChain = true;
+ } else if (SpecialPowers.compare(chain[i], window)) {
+ hasWindowInChain = true;
+ }
+ }
+
+ ok(hasDocumentInChain, "Should have document in event target chain!");
+ ok(hasWindowInChain, "Should have window in event target chain!");
+
+ try {
+ els.getListenerInfoFor(null);
+ ok(false, "Should have thrown an exception.");
+ } catch (ex) {
+ ok(true, "We should be still running.");
+ }
+ setTimeout(testAllListener, 0);
+}
+
+function dispatchTrusted(t, o) {
+ SpecialPowers.dispatchEvent(window, t, new Event("testevent", o));
+}
+
+function testAllListener() {
+ els = SpecialPowers.wrap(els);
+ var results = [];
+ var expectedResults =
+ [ { target: "testlevel3", phase: 3, trusted: false },
+ { target: "testlevel3", phase: 3, trusted: false },
+ { target: "testlevel3", phase: 3, trusted: true },
+ { target: "testlevel3", phase: 3, trusted: true },
+ { target: "testlevel3", phase: 3, trusted: true }
+ ];
+
+ function allListener(e) {
+ results.push({
+ target: e.target.id,
+ phase: e.eventPhase,
+ trusted: e.isTrusted
+ });
+ e.stopPropagation();
+ }
+ function allListenerTrustedOnly(e) {
+ results.push({
+ target: e.target.id,
+ phase: e.eventPhase,
+ trusted: e.isTrusted
+ });
+ e.stopPropagation();
+ }
+
+ els.addListenerForAllEvents(root, allListener, false, true);
+ var infos = els.getListenerInfoFor(root);
+ var nullTypes = 0;
+ for (var i = 0; i < infos.length; ++i) {
+ if (infos[i].type == null) {
+ ++nullTypes;
+ }
+ }
+ is(nullTypes, 1, "Should have one all-event-listener!");
+
+ els.addListenerForAllEvents(root, allListener, false, true, true);
+ els.addListenerForAllEvents(root, allListenerTrustedOnly, false, false, true);
+ l3.dispatchEvent(new Event("testevent", { bubbles: true, composed: true }));
+ dispatchTrusted(l3, { bubbles: true, composed: true });
+ els.removeListenerForAllEvents(root, allListener, false);
+ els.removeListenerForAllEvents(root, allListener, false, true);
+ els.removeListenerForAllEvents(root, allListenerTrustedOnly, false, true);
+ // make sure removeListenerForAllEvents works.
+ l3.dispatchEvent(new Event("testevent", { bubbles: true, composed : true }));
+ dispatchTrusted(l3, { bubbles: true, composed: true });
+
+ // Test the order of event listeners.
+ var clickListenerCalled = false;
+ var allListenerCalled = false;
+ function clickListener() {
+ clickListenerCalled = true;
+ ok(allListenerCalled, "Should have called '*' listener before normal listener!");
+ }
+ function allListener2() {
+ allListenerCalled = true;
+ ok(!clickListenerCalled, "Shouldn't have called click listener before '*' listener!");
+ }
+ root.onclick = null; // Remove the listener added in earlier tests.
+ root.addEventListener("click", clickListener);
+ els.addListenerForAllEvents(root, allListener2, false, true);
+ l3.dispatchEvent(new MouseEvent("click", { bubbles: true }));
+ root.removeEventListener("click", clickListener);
+ els.removeListenerForAllEvents(root, allListener2, false);
+ ok(allListenerCalled, "Should have called '*' listener");
+ ok(clickListenerCalled, "Should have called click listener");
+
+ is(results.length, expectedResults.length, "count");
+ for (var i = 0; i < expectedResults.length; ++i) {
+ for (var p in expectedResults[i]) {
+ is(results[i][p], expectedResults[i][p], p);
+ }
+ }
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTests);
+</script>
+</pre>
+<div id="testroot">
+ <div id="testlevel2">
+ <div id="testlevel3">
+ Test
+ </div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug450876.html b/dom/events/test/test_bug450876.html
new file mode 100644
index 0000000000..1f522a9e79
--- /dev/null
+++ b/dom/events/test/test_bug450876.html
@@ -0,0 +1,47 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=450876
+-->
+<head>
+ <title>Test for Bug 450876 - Crash [@ nsEventStateManager::GetNextTabbableMapArea] with img usemap and tabindex</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450876">Mozilla Bug 450876</a>
+<p id="display"><a href="#" id="a">link to focus from</a><img usemap="#a" tabindex="1"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 450876 **/
+
+function setTabFocus() {
+ // Override tab focus behavior on Mac */
+ SpecialPowers.pushPrefEnv({ set: [[ "accessibility.tabfocus", 7 ]] }, doTest);
+}
+
+function doTest() {
+ is(document.activeElement, document.body, "body element should be focused");
+ document.getElementById('a').focus();
+ is(document.activeElement, document.getElementById('a'), "link should have focus");
+ is(document.hasFocus(), true, "document should be focused");
+ synthesizeKey("KEY_Tab");
+ is(document.activeElement, document.body, "body element should be focused");
+ is(document.hasFocus(), false, "document should not be focused");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(setTabFocus);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug456273.html b/dom/events/test/test_bug456273.html
new file mode 100644
index 0000000000..1c53237b88
--- /dev/null
+++ b/dom/events/test/test_bug456273.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=456273
+-->
+<head>
+ <title>Test for Bug 456273</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=456273">Mozilla Bug 456273</a>
+<p id="display">PASS if Firefox does not crash.</p>
+<div id="content" style="display: none">
+
+</div>
+
+<div id="edit456273" contenteditable="true">text</div>
+
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 456273 **/
+
+function doTest() {
+ var ev = document.createEvent('KeyboardEvent');
+ ev.initKeyEvent("keypress", true, true, null, true, false,
+ false, false, 0, "z".charCodeAt(0));
+ SpecialPowers.dispatchEvent(window, document.getElementById('edit456273'), ev);
+
+ ok(true, "PASS");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug457672.html b/dom/events/test/test_bug457672.html
new file mode 100644
index 0000000000..7be6b79eb2
--- /dev/null
+++ b/dom/events/test/test_bug457672.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=457672
+-->
+<head>
+ <title>Test for Bug 457672</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=457672">Mozilla Bug 457672</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 457672 **/
+
+var windowBlurCount = 0;
+
+function listener(evt) {
+ if (evt.type == "focus") {
+ is(windowBlurCount, 1,
+ "Window should have got blur event when opening a new tab!");
+ document.getElementsByTagName("a")[0].focus();
+ SimpleTest.finish();
+ } else if (evt.type == "blur") {
+ ++windowBlurCount;
+ }
+ document.getElementById('log').textContent += evt.target + ":" + evt.type + "\n";
+}
+
+function startTest() {
+ SpecialPowers.pushPrefEnv({"set": [["browser.link.open_newwindow", 3]]}, function() {
+ document.getElementsByTagName("a")[0].focus();
+ // Note, focus/blur don't bubble
+ window.addEventListener("focus", listener);
+ window.addEventListener("blur", listener);
+ var subwin = window.open("about:blank", "", "");
+ subwin.addEventListener("focus", function(e) { subwin.close(); });
+ });
+}
+
+addLoadEvent(startTest);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<pre id="log">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug489671.html b/dom/events/test/test_bug489671.html
new file mode 100644
index 0000000000..4def80cba1
--- /dev/null
+++ b/dom/events/test/test_bug489671.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=489671
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 489671</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=489671"
+ >Mozilla Bug 489671</a>
+<p id="display" onclick="queueNextTest(); throw 'Got click 1';"></p>
+<script>
+// override window.onerror so it won't see our exceptions
+window.onerror = function() {}
+
+var testNum = 0;
+function doTest() {
+ switch(testNum++) {
+ case 0:
+ var event = document.createEvent("MouseEvents");
+ event.initMouseEvent("click", true, true, document.defaultView,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ $("display").dispatchEvent(event);
+ break;
+ case 1:
+ var script = document.createElement("script");
+ script.textContent = "queueNextTest(); throw 'Got click 2'";
+ document.body.appendChild(script);
+ break;
+ case 2:
+ window.setTimeout("queueNextTest(); throw 'Got click 3'", 0);
+ break;
+ case 3:
+ SimpleTest.endMonitorConsole();
+ return;
+ }
+}
+function queueNextTest() { SimpleTest.executeSoon(doTest); }
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.monitorConsole(SimpleTest.finish, [
+ { errorMessage: "uncaught exception: Got click 1" },
+ { errorMessage: "uncaught exception: Got click 2" },
+ { errorMessage: "uncaught exception: Got click 3" }
+]);
+
+doTest();
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_bug493251.html b/dom/events/test/test_bug493251.html
new file mode 100644
index 0000000000..e7c0be2d3a
--- /dev/null
+++ b/dom/events/test/test_bug493251.html
@@ -0,0 +1,181 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=493251
+-->
+<head>
+ <title>Test for Bug 493251</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=493251">Mozilla Bug 493251</a>
+<p id="display">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 493251 **/
+
+ var win;
+
+ var mouseDown = 0;
+ var mouseUp = 0;
+ var mouseClick = 0;
+
+ var keyDown = 0;
+ var keyPress = 0;
+ var keyUp = 0;
+
+ function suppressEventHandling(aSuppress) {
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+ ok(true, "suppressEventHandling: aSuppress=" + aSuppress);
+ utils.suppressEventHandling(aSuppress);
+ }
+
+ function dispatchMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers) {
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+ ok(true, "Dipatching mouse event: aType=" + aType + ", aX=" + aX + ", aY" +
+ aY + ", aButton=" + aButton + ", aClickCount=" + aClickCount +
+ ", aModifiers=" + aModifiers);
+ utils.sendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers);
+ }
+
+ function dumpEvent(aEvent) {
+ var detail = "target=" + aEvent.target + ", originalTarget=" +
+ aEvent.originalTarget + ", defaultPrevented=" +
+ aEvent.defaultPrevented + ", isTrusted=" + aEvent.isTrusted;
+ switch (aEvent.type) {
+ case "keydown":
+ case "keypress":
+ case "keyup":
+ detail += ", charCode=0x" + aEvent.charCode.toString(16) +
+ ", keyCode=0x" + aEvent.keyCode.toString(16) +
+ ", altKey=" + (aEvent.altKey ? "PRESSED" : "no") +
+ ", ctrlKey=" + (aEvent.ctrlKey ? "PRESSED" : "no") +
+ ", shiftKey=" + (aEvent.shiftKey ? "PRESSED" : "no") +
+ ", metaKey=" + (aEvent.metaKey ? "PRESSED" : "no");
+ break;
+ case "mousedown":
+ case "mouseup":
+ case "click":
+ detail += ", screenX=" + aEvent.screenX + ", screenY=" + aEvent.screenY +
+ ", clientX=" + aEvent.clientX + ", clientY=" + aEvent.clientY +
+ ", altKey=" + (aEvent.altKey ? "PRESSED" : "no") +
+ ", ctrlKey=" + (aEvent.ctrlKey ? "PRESSED" : "no") +
+ ", shiftKey=" + (aEvent.shiftKey ? "PRESSED" : "no") +
+ ", metaKey=" + (aEvent.metaKey ? "PRESSED" : "no") +
+ ", button=" + aEvent.button +
+ ", relatedTarget=" + aEvent.relatedTarget;
+ break;
+ }
+ ok(true, aEvent.type + " event is handled: " + detail);
+
+ var fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"].
+ getService(SpecialPowers.Ci.nsIFocusManager);
+ ok(true, "focused element is \"" + fm.focusedElement +
+ "\" and focused window is \"" + fm.focusedWindow +
+ "\" (the testing window is \"" + win + "\"");
+ }
+
+ function doTest() {
+ win.document.getElementsByTagName("input")[0].focus();
+ win.addEventListener("keydown",
+ function(e) { dumpEvent(e); ++keyDown; }, true);
+ win.addEventListener("keypress",
+ function(e) { dumpEvent(e); ++keyPress; }, true);
+ win.addEventListener("keyup",
+ function(e) { dumpEvent(e); ++keyUp; }, true);
+ win.addEventListener("mousedown",
+ function(e) { dumpEvent(e); ++mouseDown; }, true);
+ win.addEventListener("mouseup",
+ function(e) { dumpEvent(e); ++mouseUp; }, true);
+ win.addEventListener("click",
+ function(e) { dumpEvent(e); ++mouseClick; }, true);
+
+ ok(true, "doTest #1...");
+ synthesizeKey("a", {}, win);
+ is(keyDown, 1, "Wrong number events (1)");
+ is(keyPress, 1, "Wrong number events (2)");
+ is(keyUp, 1, "Wrong number events (3)");
+
+ ok(true, "doTest #2...");
+ suppressEventHandling(true);
+ synthesizeKey("a", {}, win);
+ is(keyDown, 1, "Wrong number events (4)");
+ is(keyPress, 1, "Wrong number events (5)");
+ is(keyUp, 1, "Wrong number events (6)");
+ suppressEventHandling(false);
+ is(keyDown, 1, "Wrong number events (7)");
+ is(keyPress, 1, "Wrong number events (8)");
+ is(keyUp, 1, "Wrong number events (9)");
+
+ setTimeout(continueTest1, 0);
+ }
+
+ function continueTest1() {
+ ok(true, "continueTest1...");
+ win.addEventListener("keydown", () => { suppressEventHandling(true); }, {once: true});
+ synthesizeKey("a", {}, win);
+ is(keyDown, 2, "Wrong number events (10)");
+ is(keyPress, 1, "Wrong number events (11)");
+ is(keyUp, 1, "Wrong number events (12)");
+ suppressEventHandling(false);
+ setTimeout(continueTest2, 0);
+ }
+
+ function continueTest2() {
+ ok(true, "continueTest2 #1...");
+ is(keyDown, 2, "Wrong number events (13)");
+ is(keyPress, 2, "Wrong number events (14)");
+ is(keyUp, 2, "Wrong number events (15)");
+
+ dispatchMouseEvent("mousedown", 5, 5, 0, 1, 0);
+ dispatchMouseEvent("mouseup", 5, 5, 0, 1, 0);
+ is(mouseDown, 1, "Wrong number events (16)");
+ is(mouseUp, 1, "Wrong number events (17)");
+ is(mouseClick, 1, "Wrong number events (18)");
+
+ ok(true, "continueTest2 #2...");
+ suppressEventHandling(true);
+ dispatchMouseEvent("mousedown", 5, 5, 0, 1, 0);
+ dispatchMouseEvent("mouseup", 5, 5, 0, 1, 0);
+ suppressEventHandling(false);
+ is(mouseDown, 1, "Wrong number events (19)");
+ is(mouseUp, 1, "Wrong number events (20)");
+ is(mouseClick, 1, "Wrong number events (21)");
+
+ setTimeout(continueTest3, 0);
+ }
+
+ function continueTest3() {
+ ok(true, "continueTest3...");
+ dispatchMouseEvent("mousedown", 5, 5, 0, 1, 0);
+ suppressEventHandling(true);
+ dispatchMouseEvent("mouseup", 5, 5, 0, 1, 0);
+ suppressEventHandling(false);
+ setTimeout(continueTest4, 1000);
+ }
+
+ function continueTest4() {
+ ok(true, "continueTest4...");
+ is(mouseDown, 2, "Wrong number events (19)");
+ is(mouseUp, 2, "Wrong number events (20)");
+ is(mouseClick, 2, "Wrong number events (21)");
+ win.close();
+ SimpleTest.finish();
+ }
+
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ win = window.open("window_bug493251.html", "_blank" , "width=500,height=500");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug508479.html b/dom/events/test/test_bug508479.html
new file mode 100644
index 0000000000..4967dd1ce8
--- /dev/null
+++ b/dom/events/test/test_bug508479.html
@@ -0,0 +1,110 @@
+<html>
+<head>
+ <title>Tests for the dragstart event</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+
+<script>
+
+var gGotHandlingDrop = false;
+var gGotNotHandlingDrop = false;
+
+SimpleTest.waitForExplicitFinish();
+
+function fireEvent(target, event) {
+ SpecialPowers.DOMWindowUtils.dispatchDOMEventViaPresShellForTesting(target, event);
+}
+
+async function fireDrop(element, shouldAllowDrop, shouldAllowOnlyChromeDrop) {
+ var ds = SpecialPowers.Cc["@mozilla.org/widget/dragservice;1"].
+ getService(SpecialPowers.Ci.nsIDragService);
+
+ var dataTransfer;
+ var trapDrag = function(event) {
+ dataTransfer = event.dataTransfer;
+ dataTransfer.setData("text/plain", "Hello");;
+ dataTransfer.dropEffect = "move";
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ // need to use real mouse action
+ window.addEventListener("dragstart", trapDrag, true);
+ await synthesizePlainDragAndDrop({
+ srcElement: element,
+ stepX: 9,
+ stepY: 9,
+ expectCancelDragStart: true,
+ });
+ window.removeEventListener("dragstart", trapDrag, true);
+
+ ds.startDragSessionForTests(
+ SpecialPowers.Ci.nsIDragService.DRAGDROP_ACTION_MOVE |
+ SpecialPowers.Ci.nsIDragService.DRAGDROP_ACTION_COPY |
+ SpecialPowers.Ci.nsIDragService.DRAGDROP_ACTION_LINK
+ ); // Session for emulating dnd coming from another app.
+ try {
+ var event = document.createEvent("DragEvent");
+ event.initDragEvent("dragover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
+ fireEvent(element, event);
+
+ is(ds.getCurrentSession().canDrop, shouldAllowDrop, "Unexpected .canDrop");
+ is(ds.getCurrentSession().onlyChromeDrop, shouldAllowOnlyChromeDrop,
+ "Unexpected .onlyChromeDrop");
+
+ event = document.createEvent("DragEvent");
+ event.initDragEvent("drop", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
+ fireEvent(element, event);
+ } finally {
+ ds.endDragSession(false);
+ ok(!ds.getCurrentSession(), "There shouldn't be a drag session anymore!");
+ }
+}
+
+var chromeGotEvent = false;
+function chromeListener(e) {
+ chromeGotEvent = true;
+}
+
+async function runTests()
+{
+ var targetHandling = document.getElementById("handling_target");
+ await fireDrop(targetHandling, true, false);
+
+ is(gGotHandlingDrop, true, "Got drop on accepting element (1)");
+ is(gGotNotHandlingDrop, false, "Didn't get drop on unaccepting element (1)");
+
+ // reset
+ gGotHandlingDrop = false;
+ gGotNotHandlingDrop = false;
+
+ SpecialPowers.addChromeEventListener("drop", chromeListener, true, false);
+ var targetNotHandling = document.getElementById("nothandling_target");
+ await fireDrop(targetNotHandling, true, true);
+ SpecialPowers.removeChromeEventListener("drop", chromeListener, true);
+ ok(chromeGotEvent, "Chrome should have got drop event!");
+ is(gGotHandlingDrop, false, "Didn't get drop on accepting element (2)");
+ is(gGotNotHandlingDrop, false, "Didn't get drop on unaccepting element (2)");
+
+ SimpleTest.finish();
+}
+
+</script>
+
+<body onload="window.setTimeout(runTests, 0);">
+
+<img style="width: 100px; height: 100px;"
+ src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"
+ id="handling_target"
+ ondragenter="event.preventDefault()"
+ ondragover="event.preventDefault()"
+ ondrop="gGotHandlingDrop = true;">
+
+<img style="width: 100px; height: 100px;"
+ src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"
+ id="nothandling_target"
+ ondrop="gGotNotHandlingDrop = true;">
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug517851.html b/dom/events/test/test_bug517851.html
new file mode 100644
index 0000000000..a550ea55be
--- /dev/null
+++ b/dom/events/test/test_bug517851.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=517851
+-->
+<head>
+ <title>Test for Bug 517851</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=517851">Mozilla Bug 517851</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="subframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 517851 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+window.handledCount = 0;
+window.testReturnValue = false;
+var target = document.createElement("div");
+var target2 = $("subframe").contentDocument.body;
+target.setAttribute("onerror", "++window.handledCount; return window.testReturnValue;");
+target2.setAttribute("onerror", "++window.parent.handledCount; return window.parent.testReturnValue;");
+target.setAttribute("onmouseover", "++window.handledCount; return window.testReturnValue;");
+target.setAttribute("onbeforeunload", "++window.handledCount; return window.testReturnValue;");
+target2.setAttribute("onbeforeunload", "++window.parent.handledCount; return window.parent.testReturnValue;");
+target.setAttribute("onmousemove", "++window.handledCount; return window.testReturnValue;");
+
+var e = new ErrorEvent("error", {bubbles: true, cancelable: true});
+window.testReturnValue = true;
+is(target.dispatchEvent(e), window.testReturnValue,
+ "error event should not have reverse return value handling on div!");
+is(handledCount, 1, "Wrong event count!");
+window.testReturnValue = false;
+is(target.dispatchEvent(e), window.testReturnValue,
+ "error event should not have reverse return value handling on div (2)!");
+is(handledCount, 2, "Wrong event count!");
+
+var e = new ErrorEvent("error", {bubbles: true, cancelable: true});
+window.testReturnValue = false;
+is(target2.dispatchEvent(e), !window.testReturnValue,
+ "error event should have reverse return value handling!");
+is(handledCount, 3, "Wrong event count!");
+window.testReturnValue = true;
+is(target2.dispatchEvent(e), !window.testReturnValue,
+ "error event should have reverse return value handling (2)!");
+is(handledCount, 4, "Wrong event count!");
+
+e = document.createEvent("MouseEvent");
+e.initEvent("mouseover", true, true);
+window.testReturnValue = true;
+is(target.dispatchEvent(e), window.testReturnValue,
+ "mouseover event should not have reverse return value handling!");
+is(handledCount, 5, "Wrong event count!");
+window.testReturnValue = false;
+is(target.dispatchEvent(e), window.testReturnValue,
+ "mouseover event should not have reverse return value handling (2)!");
+is(handledCount, 6, "Wrong event count!");
+
+e = document.createEvent("BeforeUnloadEvent");
+e.initEvent("beforeunload", true, true);
+window.testReturnValue = true;
+is(target.dispatchEvent(e), true,
+ "beforeunload event on random element should not be prevented!");
+is(handledCount, 6, "Wrong event count; handler should not have run!");
+is(target2.dispatchEvent(e), false,
+ "beforeunload event should be prevented!");
+is(handledCount, 7, "Wrong event count!");
+window.testReturnValue = false;
+is(target.dispatchEvent(e), false,
+ "beforeunload event on random element should be prevented because the event was already cancelled!");
+is(handledCount, 7, "Wrong event count; handler should not have run! (2)");
+
+e = document.createEvent("BeforeUnloadEvent");
+e.initEvent("beforeunload", true, true);
+window.testReturnValue = false;
+is(target.dispatchEvent(e), true,
+ "beforeunload event on random element should not be prevented (2)!");
+is(handledCount, 7, "Wrong event count; handler should not have run! (2)");
+
+is(target2.dispatchEvent(e), false,
+ "beforeunload event should be prevented (2)!");
+is(handledCount, 8, "Wrong event count!");
+
+// Create normal event for beforeunload.
+e = document.createEvent("Event");
+e.initEvent("beforeunload", true, true);
+window.testReturnValue = true;
+is(target.dispatchEvent(e), true,
+ "beforeunload event shouldn't be prevented (3)!");
+is(handledCount, 8, "Wrong event count: handler should not have run(3)!");
+is(target2.dispatchEvent(e), true,
+ "beforeunload event shouldn't be prevented (3)!");
+is(handledCount, 9, "Wrong event count!");
+
+e = document.createEvent("MouseEvent");
+e.initEvent("mousemove", true, true);
+window.testReturnValue = true;
+is(target.dispatchEvent(e), window.testReturnValue,
+ "mousemove event shouldn't have reverse return value handling!");
+is(handledCount, 10, "Wrong event count!");
+window.testReturnValue = false;
+is(target.dispatchEvent(e), window.testReturnValue,
+ "mousemove event shouldn't have reverse return value handling (2)!");
+is(handledCount, 11, "Wrong event count!");
+
+// Now unhook the beforeunload handler in the subframe, so we don't prompt to
+// unload.
+target2.onbeforeunload = null;
+
+SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug524674.xhtml b/dom/events/test/test_bug524674.xhtml
new file mode 100644
index 0000000000..d1ed83d8b1
--- /dev/null
+++ b/dom/events/test/test_bug524674.xhtml
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=524674
+-->
+<window title="Mozilla Bug 524674"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=524674"
+ target="_blank">Mozilla Bug 524674</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 524674 **/
+
+ var els = Cc["@mozilla.org/eventlistenerservice;1"]
+ .getService(Ci.nsIEventListenerService);
+
+ function dummyListener() {}
+
+ var runningTest = null;
+ var d = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+ var xhr = new XMLHttpRequest();
+
+ // Test also double removals and such.
+ var tests = [
+ function() {
+ els.addListenerChangeListener(changeListener);
+ d.addEventListener("foo", dummyListener);
+ d.addEventListener("foo", dummyListener);
+ xhr.addEventListener("foo", dummyListener);
+ tests[0] = [{target: d, listeners: ["onfoo"]},
+ {target: xhr, listeners: ["onfoo"]}];
+ },
+ function() {
+ d.addEventListener("bar", dummyListener);
+ d.addEventListener("baz", dummyListener);
+ xhr.addEventListener("bar", dummyListener);
+ xhr.addEventListener("baz", dummyListener);
+ tests[0] = [{target: d, listeners: ["onbaz", "onbar"]},
+ {target: xhr, listeners: ["onbaz", "onbar"]}];
+ },
+ function() {
+ d.onclick = dummyListener;
+ d.onclick = dummyListener;
+ xhr.onload = dummyListener;
+ tests[0] = [{target: d, listeners: ["onclick"]},
+ {target: xhr, listeners: ["onload"]}];
+ },
+ function() {
+ d.onclick = function() {};
+ tests[0] = [{target: d, listeners: ["onclick"]}];
+ },
+ function() {
+ d.removeEventListener("foo", dummyListener);
+ d.removeEventListener("foo", dummyListener);
+ xhr.removeEventListener("foo", dummyListener);
+ tests[0] = [{target: d, listeners: ["onfoo"]},
+ {target: xhr, listeners: ["onfoo"]}];
+ },
+ function() {
+ d.removeEventListener("bar", dummyListener);
+ d.removeEventListener("baz", dummyListener);
+ xhr.removeEventListener("bar", dummyListener);
+ xhr.removeEventListener("baz", dummyListener);
+ tests[0] = [{target: d, listeners: ["onbar", "onbaz"]},
+ {target: xhr, listeners: ["onbar", "onbaz"]}];
+ },
+ function() {
+ d.onclick = null;
+ d.onclick = null;
+ xhr.onload = null;
+ tests[0] = [{target: d, listeners: ["onclick"]},
+ {target: xhr, listeners: ["onload"]}];
+ },
+ function() {
+ els.removeListenerChangeListener(changeListener);
+ // Check that once we've removed the change listener, it isn't called anymore.
+ d.addEventListener("foo", dummyListener);
+ xhr.addEventListener("foo", dummyListener);
+ SimpleTest.executeSoon(function() {
+ SimpleTest.finish();
+ });
+ }
+ ];
+
+ SimpleTest.executeSoon(tests[0]);
+
+ function changeListener(array) {
+ if (typeof tests[0] == "function") {
+ return;
+ }
+ var expectedEventChanges = tests[0];
+ var eventChanges = array.enumerate();
+ var i = 0;
+ while (eventChanges.hasMoreElements() && i < expectedEventChanges.length) {
+ var current;
+ try {
+ current = eventChanges.getNext().QueryInterface(Ci.nsIEventListenerChange);
+ var expected = expectedEventChanges[i];
+
+ if (current.target == expected.target) {
+ is(current.target, expected.target, current.target + " = " + expected.target);
+ ++i;
+ }
+ } catch(ex) {
+ continue;
+ }
+ }
+ if (expectedEventChanges.length != i) {
+ return;
+ }
+
+ is(expectedEventChanges.length, i, "Should have got notification for all the changes.");
+ tests.shift();
+
+ ok(tests.length);
+ SimpleTest.executeSoon(tests[0]);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ ]]>
+ </script>
+</window>
diff --git a/dom/events/test/test_bug534833.html b/dom/events/test/test_bug534833.html
new file mode 100644
index 0000000000..d8b2000f25
--- /dev/null
+++ b/dom/events/test/test_bug534833.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=534833
+-->
+<head>
+ <title>Test for Bug 534833</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=534833">Mozilla Bug 534833</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 534833 **/
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTests);
+
+var input1GotClick = 0;
+var input2GotClick = 0;
+var textarea1GotClick = 0;
+var textarea2GotClick = 0;
+var div1GotClick = 0;
+var div2GotClick = 0;
+
+var tests = [ { element: "text", clickText: true },
+ { element: "text2", clickText: false },
+ { element: "area", clickText: true },
+ { element: "area2", clickText: false },
+ { element: "d", clickText: true },
+ { element: "d", clickText: false },
+ { element: "d2", clickText: true },
+ { element: "d2", clickText: false }
+ ];
+
+function nextTest_() {
+ if (!tests.length) {
+ finishTests();
+ return;
+ }
+
+ var test = tests.shift();
+ var el = document.getElementById(test.element);
+ el.scrollIntoView(true);
+ if (test.clickText) {
+ synthesizeMouse(el, 5, 5, {type : "mousedown" });
+ synthesizeMouse(el, 5, 5, {type : "mouseup" });
+ } else {
+ synthesizeMouse(el, el.getBoundingClientRect().width - 5, 5, {type : "mousedown" });
+ synthesizeMouse(el, el.getBoundingClientRect().width - 5, 5, {type : "mouseup" });
+ }
+ nextTest();
+}
+
+function nextTest() {
+ var el = document.getElementById("initialfocus");
+
+ el.addEventListener("focus", function() {
+ setTimeout(nextTest_, 0);
+ }, {once: true});
+ el.focus();
+}
+
+function runTests() {
+ var t = document.getElementById("text");
+ var t2 = document.getElementById("text2");
+ var a = document.getElementById("area");
+ var a2 = document.getElementById("area2");
+ var d = document.getElementById("d");
+ var d2 = document.getElementById("d2");
+
+ // input 1
+ t.onfocus = function(e) {
+ t.value = "";
+ }
+ t.onclick = function(e) {
+ ++input1GotClick;
+ }
+
+ // input 2
+ t2.onfocus = function(e) {
+ t2.value = "";
+ }
+ t2.onclick = function(e) {
+ ++input2GotClick;
+ }
+
+ // textarea 1
+ a.onfocus = function(e) {
+ a.value = "";
+ }
+ a.onclick = function(e) {
+ ++textarea1GotClick;
+ }
+
+ // textarea 2
+ a2.onfocus = function(e) {
+ a2.value = "";
+ }
+ a2.onclick = function(e) {
+ ++textarea2GotClick;
+ }
+
+ // div 1
+ var c = 0;
+ d.onmousedown = function(e) {
+ d.textContent = (++c) + " / click before or after |";
+ }
+ d.onclick = function(e) {
+ ++div1GotClick;
+ }
+
+ // div 2
+ var c2 = 0;
+ d2.onmousedown = function(e) {
+ d2.firstChild.data = (++c2) + " / click before or after |";
+ }
+ d2.onclick = function(e) {
+ ++div2GotClick;
+ }
+ nextTest();
+}
+
+function finishTests() {
+ is(input1GotClick, 1, "input element should have got a click!");
+ is(input2GotClick, 1, "input element should have got a click! (2)");
+ is(textarea1GotClick, 1, "textarea element should have got a click!");
+ is(textarea2GotClick, 1, "textarea element should have got a click! (2)");
+ is(div1GotClick, 2, "div element's content text was replaced, it should have got 2 click!");
+ is(div2GotClick, 2, "div element's content text was modified, it should have got 2 clicks!");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+<input type="text" id="initialfocus"><br>
+<input type="text" id="text" value="click before |" style="width: 95%;"><br>
+<input type="text" id="text2" value="click after |" style="width: 95%;">
+<br>
+<textarea id="area" rows="2" style="width: 95%;">
+ click before
+ |
+</textarea><br>
+<textarea id="area2" rows="2" style="width: 95%;">
+ click after |
+</textarea>
+<div id="d" style="border: 1px solid black;">click before or after |</div>
+<div id="d2" style="border: 1px solid black;">click before or after |</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug545268.html b/dom/events/test/test_bug545268.html
new file mode 100644
index 0000000000..da4d0d1649
--- /dev/null
+++ b/dom/events/test/test_bug545268.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=545268
+-->
+<head>
+ <title>Test for Bug 545268</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545268">Mozilla Bug 545268</a>
+<p id="display">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 545268
+ Like the test for bug 493251, but we test that suppressing events in
+ a parent window stops the events from reaching the child window. */
+
+ var win;
+ var subwin;
+
+ var mouseDown = 0;
+ var mouseUp = 0;
+ var mouseClick = 0;
+
+ var keyDown = 0;
+ var keyPress = 0;
+ var keyUp = 0;
+
+ function doTest() {
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+ var f = win.document.getElementById("f");
+ subwin = f.contentWindow;
+ subwin.document.getElementsByTagName("input")[0].focus();
+ subwin.addEventListener("keydown", function(e) { ++keyDown; }, true);
+ subwin.addEventListener("keypress", function(e) { ++keyPress; }, true);
+ subwin.addEventListener("keyup", function(e) { ++keyUp; }, true);
+ subwin.addEventListener("mousedown", function(e) { ++mouseDown; }, true);
+ subwin.addEventListener("mouseup", function(e) { ++mouseUp; }, true);
+ subwin.addEventListener("click", function(e) { ++mouseClick; }, true);
+
+ synthesizeKey("a", {}, subwin);
+ is(keyDown, 1, "Wrong number events (1)");
+ is(keyPress, 1, "Wrong number events (2)");
+ is(keyUp, 1, "Wrong number events (3)");
+
+ // Test that suppressing events on the parent window prevents key
+ // events in the subdocument window
+ utils.suppressEventHandling(true);
+ synthesizeKey("a", {}, subwin);
+ is(keyDown, 1, "Wrong number events (4)");
+ is(keyPress, 1, "Wrong number events (5)");
+ is(keyUp, 1, "Wrong number events (6)");
+ utils.suppressEventHandling(false);
+ is(keyDown, 1, "Wrong number events (7)");
+ is(keyPress, 1, "Wrong number events (8)");
+ is(keyUp, 1, "Wrong number events (9)");
+
+ setTimeout(continueTest1, 0);
+ }
+
+ function continueTest1() {
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+ subwin.addEventListener("keydown", () => { utils.suppressEventHandling(true); }, {once: true});
+ synthesizeKey("a", {}, subwin);
+ is(keyDown, 2, "Wrong number events (10)");
+ is(keyPress, 1, "Wrong number events (11)");
+ is(keyUp, 1, "Wrong number events (12)");
+ utils.suppressEventHandling(false);
+ setTimeout(continueTest2, 0);
+ }
+
+ function continueTest2() {
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+ is(keyDown, 2, "Wrong number events (13)");
+ is(keyPress, 2, "Wrong number events (14)");
+ is(keyUp, 2, "Wrong number events (15)");
+
+ utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
+ utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
+ is(mouseDown, 1, "Wrong number events (16)");
+ is(mouseUp, 1, "Wrong number events (17)");
+ is(mouseClick, 1, "Wrong number events (18)");
+
+ utils.suppressEventHandling(true);
+ utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
+ utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
+ utils.suppressEventHandling(false);
+ is(mouseDown, 1, "Wrong number events (19)");
+ is(mouseUp, 1, "Wrong number events (20)");
+ is(mouseClick, 1, "Wrong number events (21)");
+
+ setTimeout(continueTest3, 0);
+ }
+
+ function continueTest3() {
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+ utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
+ utils.suppressEventHandling(true);
+ utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
+ utils.suppressEventHandling(false);
+ setTimeout(continueTest4, 1000);
+ }
+
+ function continueTest4() {
+ is(mouseDown, 2, "Wrong number events (19)");
+ is(mouseUp, 2, "Wrong number events (20)");
+ is(mouseClick, 2, "Wrong number events (21)");
+ win.close();
+ SimpleTest.finish();
+ }
+
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ win = window.open("bug545268.html", "" , "");
+ win.onload = doTest;
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug547996-1.html b/dom/events/test/test_bug547996-1.html
new file mode 100644
index 0000000000..6ff112c555
--- /dev/null
+++ b/dom/events/test/test_bug547996-1.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=547996
+-->
+<head>
+ <title>Test for Bug 547996</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=547996">Mozilla Bug 547996</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 547996 **/
+/* mouseEvent.mozInputSource attribute */
+
+function prepareListener(eventName, expectedValue) {
+ return function(event) {
+ is(event.mozInputSource, expectedValue, "Correct .mozInputSource value in " + eventName);
+ };
+}
+
+const INPUT_SOURCE_UNKNOWN = MouseEvent.MOZ_SOURCE_UNKNOWN;
+const INPUT_SOURCE_KEYBOARD = MouseEvent.MOZ_SOURCE_KEYBOARD;
+
+function doTest() {
+ var eventNames = [
+ "mousedown",
+ "mouseup",
+ "click",
+ "dblclick",
+ "contextmenu",
+ "DOMMouseScroll",
+ "dragdrop",
+ "dragstart",
+ "dragend",
+ "dragenter",
+ "dragleave",
+ "dragover"
+ ];
+
+ var target = document.getElementById("testTarget");
+
+ for (var i in eventNames) {
+ for(var value = INPUT_SOURCE_UNKNOWN; value <= INPUT_SOURCE_KEYBOARD; value++) {
+ var eventName = eventNames[i];
+ var listener = prepareListener(eventName, value);
+
+ target.addEventListener(eventName, listener);
+
+ var newEvent = document.createEvent("MouseEvent");
+ newEvent.initNSMouseEvent(eventName, true, true, window, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null, 0, value);
+ target.dispatchEvent(newEvent);
+ target.removeEventListener(eventName, listener);
+ }
+
+ // Events created by script that do not initialize the mozInputSource
+ // value should have the value MOZ_SOURCE_UNKNOWN
+ var listener = prepareListener(eventName, INPUT_SOURCE_UNKNOWN);
+ target.addEventListener(eventName, listener);
+
+ var newEvent = document.createEvent("MouseEvent");
+ newEvent.initMouseEvent(eventName, true, true, window, 0, 0, 0, 0, 0,
+ false, false, false, false, 0, null);
+ target.dispatchEvent(newEvent);
+ target.removeEventListener(eventName, listener);
+
+ }
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+</script>
+</pre>
+<span id="testTarget" style="border: 1px solid black;">testTarget</span>
+</body>
+</html>
diff --git a/dom/events/test/test_bug547996-2.xhtml b/dom/events/test/test_bug547996-2.xhtml
new file mode 100644
index 0000000000..70ee797ab7
--- /dev/null
+++ b/dom/events/test/test_bug547996-2.xhtml
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=547996
+-->
+<head>
+ <title>Test for Bug 547996</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=547996">Mozilla Bug 547996</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript"><![CDATA[
+
+/** Test for Bug 547996 **/
+/* mouseEvent.mozInputSource attribute */
+
+var expectedInputSource = null;
+
+function check(event) {
+ is(event.mozInputSource, expectedInputSource, ".mozInputSource");
+}
+
+function doTest() {
+ setup();
+
+ expectedInputSource = MouseEvent.MOZ_SOURCE_KEYBOARD;
+ testKeyboard();
+
+ expectedInputSource = MouseEvent.MOZ_SOURCE_MOUSE;
+ testMouse();
+
+ expectedInputSource = MouseEvent.MOZ_SOURCE_UNKNOWN;
+ testScriptedClicks();
+
+ cleanup();
+ SimpleTest.finish();
+}
+
+function testKeyboard() {
+
+ $("inputTarget").focus();
+ synthesizeKey("VK_SPACE", {});
+ synthesizeKey("VK_RETURN", {});
+
+ $("buttonTarget").focus();
+ synthesizeKey("VK_SPACE", {});
+ synthesizeKey("VK_RETURN", {});
+
+ //XUL buttons do not generate click on ENTER or SPACE,
+ //they do only on accessKey
+
+ $("anchorTarget").focus();
+ synthesizeKey("VK_RETURN", {});
+
+ synthesizeKey("VK_TAB", {});
+ synthesizeKey("VK_SPACE", {});
+ synthesizeKey("VK_RIGHT", {});
+
+ $("checkboxTarget").focus();
+ synthesizeKey("VK_SPACE", {});
+
+ var accessKeyDetails = (navigator.platform.includes("Mac")) ?
+ { ctrlKey : true } : { altKey : true, shiftKey: true };
+
+ synthesizeKey("o", accessKeyDetails);
+ synthesizeKey("t", accessKeyDetails);
+}
+
+function testMouse() {
+ synthesizeMouse($("inputTarget"), 0, 0, {});
+ synthesizeMouse($("buttonTarget"), 0, 0, {});
+ synthesizeMouse($("xulButtonTarget"), 0, 0, {});
+ synthesizeMouse($("anchorTarget"), 0, 0, {});
+ synthesizeMouse($("radioTarget1"), 0, 0, {});
+ synthesizeMouse($("radioTarget2"), 0, 0, {});
+ synthesizeMouse($("checkboxTarget"), 0, 0, {});
+}
+
+function testScriptedClicks() {
+ $("inputTarget").click();
+ $("buttonTarget").click();
+ $("xulButtonTarget").click();
+}
+
+function setup() {
+ $("inputTarget").addEventListener("click", check);
+ $("buttonTarget").addEventListener("click", check);
+ $("anchorTarget").addEventListener("click", check);
+ $("xulButtonTarget").addEventListener("click", check);
+ $("radioTarget1").addEventListener("click", check);
+ $("radioTarget2").addEventListener("click", check);
+ $("checkboxTarget").addEventListener("click", check);
+
+}
+
+function cleanup() {
+ $("inputTarget").removeEventListener("click", check);
+ $("buttonTarget").removeEventListener("click", check);
+ $("xulButtonTarget").removeEventListener("click", check);
+ $("anchorTarget").removeEventListener("click", check);
+ $("radioTarget1").removeEventListener("click", check);
+ $("radioTarget2").removeEventListener("click", check);
+ $("checkboxTarget").removeEventListener("click", check);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(doTest, window);
+
+]]></script>
+</pre>
+<input type="checkbox" id="checkboxTarget">Checkbox target</input>
+<input id="inputTarget" type="button" value="HTML Input" accesskey="o"/>
+<button id="buttonTarget">HTML Button</button>
+<xul:button id="xulButtonTarget" accesskey="t">XUL Button</xul:button>
+<a href="#" id="anchorTarget">Anchor</a>
+<input type="radio" id="radioTarget1" name="group">Radio Target 1</input>
+<input type="radio" id="radioTarget2" name="group">Radio Target 2</input>
+</body>
+</html>
diff --git a/dom/events/test/test_bug556493.html b/dom/events/test/test_bug556493.html
new file mode 100644
index 0000000000..e2b106942e
--- /dev/null
+++ b/dom/events/test/test_bug556493.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=556493
+-->
+<head>
+ <title>Test for Bug 556493</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ div {
+ border: 1px solid;
+ }
+ </style>
+</head>
+<body onload="setTimeout(runTest, 0)">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=556493">Mozilla Bug 556493</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 556493 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var downCount = 0;
+var upCount = 0;
+var clickCount = 0;
+function runTest() {
+ var d0 = document.getElementById("d0");
+ var d1 = document.getElementById("d1");
+ var d2 = document.getElementById("d2");
+
+ d0.onmousedown = function(e) { ++downCount; };
+ d0.onmouseup = function(e) { ++upCount; }
+ d0.onclick = function(e) { ++clickCount; }
+
+ synthesizeMouse(d1, 3, 3, { type: "mousedown"});
+ synthesizeMouse(d1, 3, 3, { type: "mouseup"});
+
+ is(downCount, 1, "Wrong mousedown event count!");
+ is(upCount, 1, "Wrong mouseup event count!");
+ is(clickCount, 1, "Wrong click event count!");
+
+ synthesizeMouse(d1, 3, 3, { type: "mousedown"});
+ synthesizeMouse(d1, 30, 3, { type: "mouseup"});
+
+ is(downCount, 2, "Wrong mousedown event count!");
+ is(upCount, 2, "Wrong mouseup event count!");
+ is(clickCount, 2, "Wrong click event count!");
+
+ synthesizeMouse(d1, 3, 3, { type: "mousedown"});
+ synthesizeMouse(d2, 3, 3, { type: "mouseup"});
+
+ is(downCount, 3, "Wrong mousedown event count!");
+ is(upCount, 3, "Wrong mouseup event count!");
+ is(clickCount, 3, "Wrong click event count!");
+
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+<div id="d0">
+Test divs --
+<div id="d1">t</div><div id="d2">t</div>
+--
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug563329.html b/dom/events/test/test_bug563329.html
new file mode 100644
index 0000000000..fd4e9fd8a6
--- /dev/null
+++ b/dom/events/test/test_bug563329.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=563329
+-->
+<head>
+ <title>Test for Bug 563329</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=563329">Mozilla Bug 563329</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 563329 **/
+/* ui.click_hold_context_menus preference */
+
+var target = null;
+var testGen = getTests();
+var currentTest = null;
+
+function* getTests() {
+ let tests = [
+ { "func": function() { setTimeout(doCheckContextMenu, 100)}, "message": "Context menu should has fired"},
+ { "func": function() { setTimeout(doCheckDuration, 100)}, "message": "Context menu should has fired with delay"},
+ { "func": function() { setTimeout(finishTest, 100)}, "message": "" }
+ ];
+
+ let i = 0;
+ while (i < tests.length)
+ yield tests[i++];
+}
+
+function doTest() {
+ target = document.getElementById("testTarget");
+
+ document.documentElement.addEventListener("contextmenu", function() {
+ SimpleTest.ok(true, currentTest.message);
+ synthesizeMouse(target, 0, 0, {type: "mouseup"});
+ SimpleTest.executeSoon(function() {
+ currentTest = testGen.next();
+ currentTest.func();
+ });
+ });
+
+ SimpleTest.executeSoon(function() {
+ currentTest = testGen.next();
+ currentTest.func();
+ });
+}
+
+function doCheckContextMenu() {
+ synthesizeMouse(target, 0, 0, {type: "mousedown"});
+}
+
+function doCheckDuration() {
+ var duration = 50;
+
+ // Change click hold delay
+ SpecialPowers.pushPrefEnv({"set":[["ui.click_hold_context_menus.delay", duration]]}, function() { synthesizeMouse(target, 0, 0, {type: "mousedown"}); });
+}
+
+function finishTest() {
+ synthesizeKey("VK_ESCAPE", {}, window);
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ SpecialPowers.pushPrefEnv({"set":[["ui.click_hold_context_menus", true]]}, doTest);
+});
+</script>
+</pre>
+<span id="testTarget" style="border: 1px solid black;">testTarget</span>
+</body>
+</html>
diff --git a/dom/events/test/test_bug574663.html b/dom/events/test/test_bug574663.html
new file mode 100644
index 0000000000..164fdcf41d
--- /dev/null
+++ b/dom/events/test/test_bug574663.html
@@ -0,0 +1,193 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=574663
+-->
+<head>
+ <title>Test for Bug 574663</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=574663">Mozilla Bug 574663</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 574663 **/
+
+// SimpleTest's paint_listener does not work on other windows, so we inline
+// a smaller version here.
+function waitForPaint(win, utils, callback) {
+ win.document.documentElement.getBoundingClientRect();
+ if (!utils.isMozAfterPaintPending) {
+ win.requestAnimationFrame(function() {
+ setTimeout(callback);
+ });
+ return;
+ }
+
+ var onpaint = function() {
+ if (!utils.isMozAfterPaintPending) {
+ win.removeEventListener("MozAfterPaint", onpaint);
+ callback();
+ return;
+ }
+ if (utils.isTestControllingRefreshes) {
+ utils.advanceTimeAndRefresh(0);
+ }
+ }
+ win.addEventListener("MozAfterPaint", onpaint);
+ if (utils.isTestControllingRefreshes) {
+ utils.advanceTimeAndRefresh(0);
+ }
+}
+
+// This is a magic number representing how many device pixels we are attempting to
+// scroll or zoom. We use it for sending the wheel events, but we don't actually
+// check that we have scrolled by that amount.
+var kDelta = 3;
+
+function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum, callback) {
+ var win = scrollbox.ownerDocument.defaultView;
+ let winUtils = SpecialPowers.getDOMWindowUtils(win);
+
+ let event = {
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaY: direction * kDelta,
+ lineOrPageDeltaY: direction,
+ ctrlKey: ctrl,
+ isMomentum: momentum
+ };
+
+ // Construct a promise that will resolve when either scroll or zoom has changed.
+ // --- Intermittent Warning ---
+ // Two wheel events are sent, but our promise resolves when any change has been
+ // made to scroll or zoom. That makes it possible that the effect of the second
+ // event may not yet be applied when the promise resolves. This shouldn't lead
+ // to any errors, since the two wheel events are moving in the same direction,
+ // and our later checks will only ensure that the value has changed from its
+ // initial value. This was done intentionally, because attempting to wait after
+ // both events yields problems when the second event has no effect, which does
+ // happen in testing. It's not clear why this is happening. Since the testing
+ // pattern is scroll (twice), then scroll back (twice), it's possible that the
+ // first scroll back event is sufficient to return the scrollbox to its minimal
+ // scrollTop position, and so the second event doesn't scroll any further.
+ const initialZoom = winUtils.fullZoom;
+ const initialScroll = scrollbox.scrollTop;
+
+ const effectOfWheelEvent = SimpleTest.promiseWaitForCondition(() => {
+ return ((winUtils.fullZoom != initialZoom) || (scrollbox.scrollTop != initialScroll));
+ }, "Mouse wheel should have caused us to either zoom or scroll.");
+
+ synthesizeWheel(scrollbox, 10, 10, event, win);
+
+ // then additional pixel scroll
+ event.lineOrPageDeltaY = 0;
+ synthesizeWheel(scrollbox, 10, 10, event, win);
+
+ effectOfWheelEvent.then(callback);
+}
+
+function runTest() {
+ var win = open('bug574663.html', '_blank', 'width=300,height=300');
+ let winUtils = SpecialPowers.getDOMWindowUtils(win);
+
+ let waitUntilPainted = function(callback) {
+ // Until the first non-blank paint, the parent will set the opacity of our
+ // browser to 0 using the 'blank' attribute.
+ // Until the blank attribute is removed, we can't send scroll events.
+ SimpleTest.waitForFocus(function() {
+ /* eslint-disable no-shadow */
+ let chromeScript = SpecialPowers.loadChromeScript(_ => {
+ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ win.requestAnimationFrame(() => {
+ win.gBrowser.selectedBrowser.removeAttribute("blank");
+ win.requestAnimationFrame(() => {
+ sendAsyncMessage("blank-attribute-removed");
+ });
+ });
+ });
+ /* eslint-enable no-shadow */
+ chromeScript.promiseOneMessage("blank-attribute-removed").then(() => {
+ chromeScript.destroy();
+ waitForPaint(win, winUtils, callback);
+ });
+ }, win);
+ };
+
+ waitUntilPainted(function () {
+ var scrollbox = win.document.getElementById("scrollbox");
+ let outstandingTests = [
+ [false, false],
+ [false, true],
+ [true, false],
+ [true, true],
+ ];
+
+ // grab the refresh driver, since we want to make sure
+ // async scrolls happen in deterministic time
+ winUtils.advanceTimeAndRefresh(1000);
+
+ function nextTest() {
+ let [ctrlKey, isMomentum] = outstandingTests.shift();
+ let scrollTopBefore = scrollbox.scrollTop;
+ let zoomFactorBefore = winUtils.fullZoom;
+
+ let check = function() {
+ if (!ctrlKey) {
+ let postfix = isMomentum ? ", even after releasing the touchpad" : "";
+ // Normal scroll: scroll
+ is(winUtils.fullZoom, zoomFactorBefore, "Normal scrolling shouldn't change zoom" + postfix);
+ isnot(scrollbox.scrollTop, scrollTopBefore,
+ "Normal scrolling should scroll" + postfix);
+ } else {
+ if (!isMomentum) {
+ isnot(winUtils.fullZoom, zoomFactorBefore, "Ctrl-scrolling should zoom while the user is touching the touchpad");
+ is(scrollbox.scrollTop, scrollTopBefore, "Ctrl-scrolling shouldn't scroll while the user is touching the touchpad");
+ } else {
+ is(winUtils.fullZoom, zoomFactorBefore, "Momentum scrolling shouldn't zoom, even when pressing Ctrl");
+ isnot(scrollbox.scrollTop, scrollTopBefore,
+ "Momentum scrolling should scroll, even when pressing Ctrl");
+ }
+ }
+
+ if (!outstandingTests.length) {
+ winUtils.restoreNormalRefresh();
+ win.close();
+ SimpleTest.finish();
+ return;
+ }
+
+ // Revert the effect for the next test.
+ sendTouchpadScrollMotion(scrollbox, -1, ctrlKey, isMomentum, function() {
+ setTimeout(nextTest, 0);
+ });
+ }
+
+ sendTouchpadScrollMotion(scrollbox, 1, ctrlKey, isMomentum, check);
+ }
+ nextTest();
+ });
+}
+
+window.onload = function() {
+ SpecialPowers.pushPrefEnv({
+ "set":[["general.smoothScroll", false],
+ ["mousewheel.acceleration.start", -1],
+ ["mousewheel.system_scroll_override_on_root_content.enabled", false],
+ ["mousewheel.with_control.action", 3]]}, runTest);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug586961.xhtml b/dom/events/test/test_bug586961.xhtml
new file mode 100644
index 0000000000..ebdcc248d6
--- /dev/null
+++ b/dom/events/test/test_bug586961.xhtml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=586961
+-->
+<window title="Mozilla Bug 586961"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+<body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=586961">Mozilla Bug 586961</a>
+
+ <p id="display"></p>
+<div id="content" style="display: none">
+</div>
+</body>
+
+<box onclick="clicked(event)">
+ <label id="controllabel" control="controlbutton" accesskey="k" value="Click here" />
+ <button id="controlbutton" label="Button" />
+</box>
+
+<script class="testbody" type="application/javascript"><![CDATA[
+
+/** Test for Bug 586961 **/
+
+function clicked(event) {
+ is(event.target.id, "controlbutton", "Accesskey was directed to controlled element.");
+ SimpleTest.finish();
+}
+
+function test() {
+ var accessKeyDetails = (navigator.platform.includes("Mac")) ?
+ { altKey : true, ctrlKey : true } :
+ { altKey : true, shiftKey: true };
+ synthesizeKey("k", accessKeyDetails);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(test, window);
+
+]]></script>
+
+</window>
diff --git a/dom/events/test/test_bug591249.xhtml b/dom/events/test/test_bug591249.xhtml
new file mode 100644
index 0000000000..c95bf501de
--- /dev/null
+++ b/dom/events/test/test_bug591249.xhtml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=591249
+-->
+<window title="Mozilla Bug 591249" onload="RunTest()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=591249">Mozilla Bug 591249</a>
+ <img id="image"
+ src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAG0lEQVR42mP8z0A%2BYKJA76jmUc2jmkc1U0EzACKcASfOgGoMAAAAAElFTkSuQmCC"
+ ondragstart="event.preventDefault();"/>
+ <iframe id="iframe" src="chrome://mochitests/content/chrome/dom/events/test/bug591249_iframe.xhtml" style="height: 300px; width: 100%;"></iframe>
+</body>
+
+<script class="testbody" type="application/javascript"><![CDATA[
+/** Test for Bug 591249 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function completeTest(aBox) {
+ ok(window.getComputedStyle(aBox).backgroundColor == "rgb(255, 0, 0)", "The -moz-drag-over style should be removed.");
+ SimpleTest.finish();
+}
+
+function fireEvent(target, event) {
+ var win = target.ownerGlobal;
+ var utils = win.windowUtils;
+ utils.dispatchDOMEventViaPresShellForTesting(target, event);
+}
+
+function RunTest() {
+ var image = document.getElementById("image");
+ var iframe = document.getElementById("iframe");
+ var iBox = iframe.contentDocument.getElementById("drop-target");
+ var insideBoxX = iBox.offsetWidth + 10;
+ var insideBoxY = iBox.offsetHeight + 10;
+
+ var dataTransfer;
+ var trapDrag = function(event) {
+ dataTransfer = event.dataTransfer;
+ dataTransfer.setData("text/plain", "Hello");
+ dataTransfer.dropEffect = "move";
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ // need to use real mouse action to get the dataTransfer
+ window.addEventListener("dragstart", trapDrag, true);
+ synthesizeMouse(image, 2, 2, { type: "mousedown" });
+ synthesizeMouse(image, 11, 11, { type: "mousemove" });
+ synthesizeMouse(image, 20, 20, { type: "mousemove" });
+ window.removeEventListener("dragstart", trapDrag, true);
+ synthesizeMouse(image, 20, 20, { type: "mouseup" });
+
+ var event = document.createEvent("DragEvent");
+ event.initDragEvent("dragover", true, true, iBox.ownerGlobal, 0, 0, 0, 0, 0, false, false, false, false, 0, iBox, dataTransfer);
+ fireEvent(iBox, event);
+ synthesizeMouse(image, 3, 3, { type: "mousedown" });
+ synthesizeMouse(image, 23, 23, { type: "mousemove" });
+ synthesizeMouse(iBox, insideBoxX, insideBoxY, { type: "mousemove" });
+ ok(window.getComputedStyle(iBox).backgroundColor == "rgb(255, 255, 0)", "The -moz-drag-over style should be applied.");
+ synthesizeMouse(iBox, insideBoxX, insideBoxY, { type: "mouseup" });
+ window.setTimeout(function () { completeTest(iBox); }, 40);
+}
+]]></script>
+
+</window>
diff --git a/dom/events/test/test_bug591815.html b/dom/events/test/test_bug591815.html
new file mode 100644
index 0000000000..c3987bb957
--- /dev/null
+++ b/dom/events/test/test_bug591815.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=591815
+-->
+<head>
+ <title>Test for Bug 591815</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="setTimeout(runTest, 0)">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=591815">Mozilla Bug 591815</a>
+<p id="display"></p>
+<div id="content">
+ <div id="wrapper">
+ <!-- 20x20 of red -->
+ <img id="image" ondragstart="fail();"
+ src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAG0lEQVR42mP8z0A%2BYKJA76jmUc2jmkc1U0EzACKcASfOgGoMAAAAAElFTkSuQmCC"/>
+ </div>
+</div>
+<pre id="test">
+
+<script type="application/javascript">
+
+/** Test for Bug 591815 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function fail() {
+ ok(false, "drag started but should not have");
+}
+
+function runTest() {
+ var image = document.getElementById("image");
+ var wrapper = document.getElementById("wrapper");
+ var preventDefault = function(event) {
+ event.preventDefault();
+ };
+ wrapper.addEventListener('mousedown', preventDefault);
+
+ synthesizeMouse(image, 3, 3, { type: "mousedown"});
+ synthesizeMouse(image, 53, 53, { type: "mousemove"});
+ synthesizeMouse(image, 53, 53, { type: "mouseup"});
+
+ wrapper.removeEventListener('mousedown', preventDefault);
+
+ var relocateElementAndPreventDefault = function(event) {
+ document.body.appendChild(wrapper);
+ event.preventDefault();
+ }
+ wrapper.addEventListener('mousedown', relocateElementAndPreventDefault);
+
+ synthesizeMouse(image, 3, 3, { type: "mousedown"});
+ synthesizeMouse(image, 53, 53, { type: "mousemove"});
+ synthesizeMouse(image, 53, 53, { type: "mouseup"});
+
+ wrapper.removeEventListener('mousedown', relocateElementAndPreventDefault);
+
+ ok(true, "passed the test");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug593959.html b/dom/events/test/test_bug593959.html
new file mode 100644
index 0000000000..a809e028c3
--- /dev/null
+++ b/dom/events/test/test_bug593959.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=593959
+-->
+<head>
+ <title>Test for Bug 593959</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ body:active {
+ background: red;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=593959">Mozilla Bug 593959</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 593959 **/
+
+ function doTest() {
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ var e = document.createEvent("MouseEvent");
+ e.initEvent("mousedown", false, false, window, 0, 1, 1, 1, 1,
+ false, false, false, false, 0, null);
+ utils.dispatchDOMEventViaPresShellForTesting(document.body, e);
+
+ is(document.querySelector("body:active"), document.body, "body should be active!")
+
+ var ifrwindow = document.getElementById("ifr").contentWindow;
+
+ var utils2 = SpecialPowers.getDOMWindowUtils(ifrwindow);
+
+ var e2 = ifrwindow.document.createEvent("MouseEvent");
+ e2.initEvent("mouseup", false, false, ifrwindow, 0, 1, 1, 1, 1,
+ false, false, false, false, 0, null);
+ utils2.dispatchDOMEventViaPresShellForTesting(ifrwindow.document.body, e2);
+
+ isnot(document.querySelector("body:active"), document.body, "body shouldn't be active!")
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+
+
+
+</script>
+</pre>
+<iframe id="ifr"></iframe>
+</body>
+</html>
diff --git a/dom/events/test/test_bug602962.xhtml b/dom/events/test/test_bug602962.xhtml
new file mode 100644
index 0000000000..aac3d5b474
--- /dev/null
+++ b/dom/events/test/test_bug602962.xhtml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=602962
+-->
+<window title="Mozilla Bug 602962" onload="openWindow()"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=602962">Mozilla Bug 602962</a>
+ <p id="display"></p>
+<div id="content" style="display: none">
+</div>
+</body>
+
+<script class="testbody" type="application/javascript"><![CDATA[
+/** Test for Bug 602962 **/
+var scrollbox, content;
+var scrollX = 0, scrollY = 0;
+
+var oldWidth = 0, oldHeight = 0;
+var win = null;
+
+function openWindow() {
+ win = window.open("chrome://mochitests/content/chrome/dom/events/test/bug602962.xhtml", "_blank", "width=600,height=600");
+}
+
+function doTest() {
+ scrollbox = win.document.getElementById("page-scrollbox");
+ content = win.document.getElementById("page-box");
+ content.style.width = 400 + "px";
+
+ win.addEventListener("resize", function() {
+ win.removeEventListener("resize", arguments.callee, false);
+
+ setTimeout(function(){
+ scrollbox.scrollBy(200,0);
+ resize();
+ },0);
+ }, false);
+
+ oldWidth = win.outerWidth;
+ oldHeight = win.outerHeight;
+ win.resizeTo(200, 400);
+}
+
+function resize() {
+ scrollX = scrollbox.scrollLeft;
+ scrollY = scrollbox.scrollTop;
+
+ win.addEventListener("resize", function() {
+ content.style.width = (oldWidth + 400) + "px";
+ win.removeEventListener("resize", arguments.callee, true);
+
+ setTimeout(function() {
+ finish();
+ }, 0);
+ }, true);
+
+ win.resizeTo(oldWidth, oldHeight);
+}
+
+function finish() {
+ if (win.outerWidth != oldWidth ||
+ win.outerHeight != oldHeight) {
+ // We should eventually get back to the original size.
+ setTimeout(finish, 0);
+ return;
+ }
+ scrollbox.scrollBy(scrollX, scrollY);
+
+ is(scrollbox.scrollLeft, 200, "Scroll Left should have been restored to the value before the resize");
+ is(scrollbox.scrollTop, 0, "Scroll Top should have been restored to the value before the resize");
+
+ is(win.outerWidth, oldWidth, "Width should be resized");
+ is(win.outerHeight, oldHeight, "Height should be resized");
+ win.close();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+]]></script>
+
+</window>
diff --git a/dom/events/test/test_bug603008.html b/dom/events/test/test_bug603008.html
new file mode 100644
index 0000000000..b52956fabc
--- /dev/null
+++ b/dom/events/test/test_bug603008.html
@@ -0,0 +1,556 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=508906
+-->
+<head>
+ <title>Test for Bug 603008</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=508906">Mozilla Bug 603008</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+
+/** Test for Bug 306008 - Touch* Events **/
+
+let tests = [], testTarget, parent;
+
+let touch = {
+ id: 0,
+ point: {x: 0, y: 0},
+ radius: {x: 0, y: 0},
+ rotation: 0,
+ force: 0.5,
+ target: null
+}
+
+function nextTest() {
+ if (tests.length)
+ SimpleTest.executeSoon(tests.shift());
+}
+
+function random() {
+ return Math.floor(Math.random() * 100);
+}
+
+function checkEvent(aFakeEvent) {
+ return function(aEvent) {
+ is(aFakeEvent.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
+ is(aFakeEvent.altKey, aEvent.altKey, "Correct altKey");
+ is(aFakeEvent.shiftKey, aEvent.shiftKey, "Correct shiftKey");
+ is(aFakeEvent.metaKey, aEvent.metaKey, "Correct metaKey");
+ checkTouches(aFakeEvent.touches, aEvent.touches);
+ checkTouches(aFakeEvent.targetTouches, aEvent.targetTouches);
+ checkTouches(aFakeEvent.changedTouches, aEvent.changedTouches);
+ }
+}
+
+function checkTouches(aTouches1, aTouches2) {
+ is(aTouches1.length, aTouches2.length, "Correct touches length");
+ for (var i = 0; i < aTouches1.length; i++) {
+ checkTouch(aTouches1[i], aTouches2[i]);
+ }
+}
+
+function checkTouch(aFakeTouch, aTouch) {
+ is(aFakeTouch.identifier, aTouch.identifier, "Touch has correct identifier");
+ is(aFakeTouch.target, aTouch.target, "Touch has correct target");
+ is(aFakeTouch.page.x, aTouch.pageX, "Touch has correct pageX");
+ is(aFakeTouch.page.y, aTouch.pageY, "Touch has correct pageY");
+ is(aFakeTouch.page.x + Math.round(window.mozInnerScreenX), aTouch.screenX, "Touch has correct screenX");
+ is(aFakeTouch.page.y + Math.round(window.mozInnerScreenY), aTouch.screenY, "Touch has correct screenY");
+ is(aFakeTouch.page.x, aTouch.clientX, "Touch has correct clientX");
+ is(aFakeTouch.page.y, aTouch.clientY, "Touch has correct clientY");
+ is(aFakeTouch.radius.x, aTouch.radiusX, "Touch has correct radiusX");
+ is(aFakeTouch.radius.y, aTouch.radiusY, "Touch has correct radiusY");
+ is(aFakeTouch.rotationAngle, aTouch.rotationAngle, "Touch has correct rotationAngle");
+ is(aFakeTouch.force, aTouch.force, "Touch has correct force");
+}
+
+function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
+ var ids = [], xs=[], ys=[], rxs = [], rys = [],
+ rotations = [], forces = [];
+
+ for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
+ for (var i = 0; i < aEvent[touchType].length; i++) {
+ if (!ids.includes(aEvent[touchType][i].identifier)) {
+ ids.push(aEvent[touchType][i].identifier);
+ xs.push(aEvent[touchType][i].page.x);
+ ys.push(aEvent[touchType][i].page.y);
+ rxs.push(aEvent[touchType][i].radius.x);
+ rys.push(aEvent[touchType][i].radius.y);
+ rotations.push(aEvent[touchType][i].rotationAngle);
+ forces.push(aEvent[touchType][i].force);
+ }
+ }
+ }
+ return windowUtils.sendTouchEvent(aType,
+ ids, xs, ys, rxs, rys,
+ rotations, forces,
+ aModifiers, 0);
+}
+
+function touchEvent(aOptions) {
+ if (!aOptions) {
+ aOptions = {};
+ }
+ this.ctrlKey = aOptions.ctrlKey || false;
+ this.altKey = aOptions.altKey || false;
+ this.shiftKey = aOptions.shiftKey || false;
+ this.metaKey = aOptions.metaKey || false;
+ this.touches = aOptions.touches || [];
+ this.targetTouches = aOptions.targetTouches || [];
+ this.changedTouches = aOptions.changedTouches || [];
+}
+
+function testtouch(aOptions) {
+ if (!aOptions)
+ aOptions = {};
+ this.identifier = aOptions.identifier || 0;
+ this.target = aOptions.target || 0;
+ this.page = aOptions.page || {x: 0, y: 0};
+ this.radius = aOptions.radius || {x: 0, y: 0};
+ this.rotationAngle = aOptions.rotationAngle || 0;
+ this.force = aOptions.force || 1;
+}
+
+function testSingleTouch(name) {
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target = document.getElementById("testTarget");
+ let target2 = document.getElementById("testTarget2");
+ let bcr = target.getBoundingClientRect();
+ let bcr2 = target2.getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ page: {x: Math.round(bcr.left + bcr.width/2),
+ y: Math.round(bcr.top + bcr.height/2)},
+ target
+ });
+ let event = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+
+ // test touchstart event fires correctly
+ var checkFunction = checkEvent(event);
+ window.addEventListener("touchstart", checkFunction);
+ sendTouchEvent(cwu, "touchstart", event, 0);
+ window.removeEventListener("touchstart", checkFunction);
+
+ // test touchmove event fires correctly
+ event.touches[0].page.x -= 1;
+ event.targetTouches[0].page.x -= 1;
+ event.changedTouches[0].page.x -= 1;
+ checkFunction = checkEvent(event);
+ window.addEventListener("touchmove", checkFunction);
+ sendTouchEvent(cwu, "touchmove", event, 0);
+ window.removeEventListener("touchmove", checkFunction);
+
+ // test touchend event fires correctly
+ event.touches = [];
+ event.targetTouches = [];
+ checkFunction = checkEvent(event);
+ window.addEventListener("touchend", checkFunction);
+ sendTouchEvent(cwu, "touchend", event, 0);
+ window.removeEventListener("touchend", checkFunction);
+
+ nextTest();
+}
+
+function testSingleTouch2(name) {
+ // firing a touchstart that includes only one touch will evict any touches in the queue with touchend messages
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target = document.getElementById("testTarget");
+ let target2 = document.getElementById("testTarget2");
+ let bcr = target.getBoundingClientRect();
+ let bcr2 = target2.getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ identifier: 0,
+ page: {x: Math.round(bcr.left + bcr.width/2),
+ y: Math.round(bcr.top + bcr.height/2)},
+ target
+ });
+ let event1 = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+ let touch2 = new testtouch({
+ identifier: 1,
+ page: {x: Math.round(bcr2.left + bcr2.width/2),
+ y: Math.round(bcr2.top + bcr2.height/2)},
+ target: target2
+ });
+ let event2 = new touchEvent({
+ touches: [touch2],
+ targetTouches: [touch2],
+ changedTouches: [touch2]
+ });
+
+ // test touchstart event fires correctly
+ var checkFunction1 = checkEvent(event1);
+ window.addEventListener("touchstart", checkFunction1);
+ sendTouchEvent(cwu, "touchstart", event1, 0);
+ window.removeEventListener("touchstart", checkFunction1);
+
+ event1.touches = [];
+ event1.targetTouches = [];
+ checkFunction1 = checkEvent(event1);
+ var checkFunction2 = checkEvent(event2);
+
+ window.addEventListener("touchend", checkFunction1);
+ window.addEventListener("touchstart", checkFunction2);
+ sendTouchEvent(cwu, "touchstart", event2, 0);
+ window.removeEventListener("touchend", checkFunction1);
+ window.removeEventListener("touchstart", checkFunction2);
+
+ sendTouchEvent(cwu, "touchstart", event1, 0);
+
+ nextTest();
+}
+
+
+function testMultiTouch(name) {
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target1 = document.getElementById("testTarget");
+ let target2 = document.getElementById("testTarget2");
+ let bcr = target1.getBoundingClientRect();
+ let bcr2 = target2.getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ identifier: 0,
+ page: {x: Math.round(bcr.left + bcr.width/2),
+ y: Math.round(bcr.top + bcr.height/2)},
+ target: target1
+ });
+ let touch2 = new testtouch({
+ identifier: 1,
+ page: {x: Math.round(bcr2.left + bcr2.width/2),
+ y: Math.round(bcr2.top + bcr2.height/2)},
+ target: target2
+ });
+ let event = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+
+ // test touchstart event fires correctly
+ var checkFunction = checkEvent(event);
+ window.addEventListener("touchstart", checkFunction);
+ sendTouchEvent(cwu, "touchstart", event, 0);
+ window.removeEventListener("touchstart", checkFunction);
+
+ event.touches.push(touch2);
+ event.targetTouches = [touch2];
+ event.changedTouches = [touch2];
+ window.addEventListener("touchstart", checkFunction);
+ sendTouchEvent(cwu, "touchstart", event, 0);
+ window.removeEventListener("touchstart", checkFunction);
+
+ // test moving one touch point
+ event.touches[0].page.x -= 1;
+ event.targetTouches = [event.touches[0]];
+ event.changedTouches = [event.touches[0]];
+ window.addEventListener("touchmove", checkFunction);
+ sendTouchEvent(cwu, "touchmove", event, 0);
+ window.removeEventListener("touchmove", checkFunction);
+
+ // test moving both touch points -- two touchmove events should fire, one on each target
+ event.touches[0].page.x -= 1;
+ event.touches[1].page.x -= 1;
+ event.targetTouches = event.touches;
+ event.changedTouches = event.touches;
+ var touchMoveEvents = 0;
+ var checkFunction2 = function(aEvent) {
+ is(event.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
+ is(event.altKey, aEvent.altKey, "Correct altKey");
+ is(event.shiftKey, aEvent.shiftKey, "Correct shiftKey");
+ is(event.metaKey, aEvent.metaKey, "Correct metaKey");
+ checkTouches(event.touches, aEvent.touches);
+ checkTouches(event.changedTouches, aEvent.changedTouches);
+ if (aEvent.targetTouches[0].target == target1) {
+ checkTouches([event.touches[0]], aEvent.targetTouches);
+ } else if (aEvent.targetTouches[0].target == target2) {
+ checkTouches([event.touches[1]], aEvent.targetTouches);
+ } else
+ ok(false, "Event target is incorrect: " + event.targetTouches[0].target.nodeName + "#" + event.targetTouches[0].target.id);
+ touchMoveEvents++;
+ };
+ window.addEventListener("touchmove", checkFunction2);
+ sendTouchEvent(cwu, "touchmove", event, 0);
+ is(touchMoveEvents, 2, "Correct number of touchmove events fired");
+ window.removeEventListener("touchmove", checkFunction2);
+
+ // test removing just one finger
+ var expected = new touchEvent({
+ touches: [touch2],
+ targetTouches: [],
+ changedTouches: [touch1]
+ });
+ checkFunction = checkEvent(expected);
+
+ event.touches = [];
+ event.targetTouches = [];
+ event.changedTouches = [touch1];
+
+ // test removing the other finger
+ window.addEventListener("touchend", checkFunction);
+ sendTouchEvent(cwu, "touchend", event, 0);
+ window.removeEventListener("touchend", checkFunction);
+
+ event.touches = [];
+ event.targetTouches = [];
+ event.changedTouches = [touch2];
+ checkFunction = checkEvent(event);
+ window.addEventListener("touchend", checkFunction);
+ sendTouchEvent(cwu, "touchend", event, 0);
+ window.removeEventListener("touchend", checkFunction);
+
+ nextTest();
+}
+
+function testTouchChanged() {
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target1 = document.getElementById("testTarget");
+ let bcr = target1.getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ identifier: 0,
+ page: {x: Math.round(bcr.left + bcr.width/2),
+ y: Math.round(bcr.top + bcr.height/2)},
+ target: target1
+ });
+ let event = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+
+ var checkFunction = checkEvent(event);
+ sendTouchEvent(cwu, "touchstart", event, 0);
+
+ var moveEvents = 0;
+ function onMove(aEvent) {
+ moveEvents++;
+ }
+
+ window.addEventListener("touchmove", onMove);
+
+ // the first touchmove should always fire an event
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // changing nothing should not fire a touchmove event
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // test moving x
+ event.touches[0].page.x -= 1;
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // test moving y
+ event.touches[0].page.y -= 1;
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // test changing y radius
+ event.touches[0].radius.y += 1;
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // test changing x radius
+ event.touches[0].radius.x += 1;
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // test changing rotationAngle
+ event.touches[0].rotationAngle += 1;
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // test changing force
+ event.touches[0].force += 1;
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ // changing nothing again
+ sendTouchEvent(cwu, "touchmove", event, 0);
+
+ is(moveEvents, 7, "Six move events fired");
+
+ window.removeEventListener("touchmove", onMove);
+ sendTouchEvent(cwu, "touchend", event, 0);
+ nextTest();
+}
+
+function testPreventDefault() {
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target = document.getElementById("testTarget");
+ let target2 = document.getElementById("testTarget2");
+ let bcr = target.getBoundingClientRect();
+ let bcr2 = target2.getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ page: {x: bcr.left + bcr.width/2,
+ y: bcr.top + bcr.height/2},
+ target
+ });
+ let event = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+
+ let preventFunction = function(aEvent) {
+ aEvent.preventDefault();
+ }
+
+ let subTests = [
+ [{ name: "touchstart", prevent: false },
+ { name: "touchmove", prevent: false },
+ { name: "touchmove", prevent: false },
+ { name: "touchend", prevent: false }],
+ [{ name: "touchstart", prevent: true, doPrevent: true },
+ { name: "touchmove", prevent: false },
+ { name: "touchmove", prevent: false },
+ { name: "touchend", prevent: false }],
+ [{ name: "touchstart", prevent: false },
+ { name: "touchmove", prevent: true, doPrevent: true },
+ { name: "touchmove", prevent: false },
+ { name: "touchend", prevent: false }],
+ [{ name: "touchstart", prevent: false },
+ { name: "touchmove", prevent: false },
+ { name: "touchmove", prevent: false, doPrevent: true },
+ { name: "touchend", prevent: false }],
+ [{ name: "touchstart", prevent: false },
+ { name: "touchmove", prevent: false },
+ { name: "touchmove", prevent: false },
+ { name: "touchend", prevent: true, doPrevent: true }]
+ ];
+
+ var dotest = function(aTest) {
+ if (aTest.doPrevent) {
+ target.addEventListener(aTest.name, preventFunction);
+ }
+
+ if (aTest.name == "touchmove") {
+ touch1.page.x++;
+ event.touches[0] = touch1;
+ }
+
+ is(sendTouchEvent(cwu, aTest.name, event, 0), aTest.prevent, "Got correct status");
+
+ if (aTest.doPrevent)
+ target.removeEventListener(aTest.name, preventFunction);
+ }
+
+ for (var i = 0; i < subTests.length; i++) {
+ for (var j = 0; j < subTests[i].length; j++) {
+ dotest(subTests[i][j]);
+ }
+ }
+
+ nextTest();
+}
+
+function testRemovingElement() {
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target = document.getElementById("testTarget");
+ let bcr = document.getElementById("testTarget").getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ page: {x: bcr.left + bcr.width/2,
+ y: bcr.top + bcr.height/2},
+ });
+ let e = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+
+ var touchEvents = 0;
+ var removeTarget = function(aEvent) {
+ aEvent.target.remove();
+ };
+
+ var checkTarget = function(aEvent) {
+ is(aEvent.target, target, "Event has correct target");
+ touchEvents++;
+ };
+
+ target.addEventListener("touchstart", removeTarget);
+ target.addEventListener("touchmove", checkTarget);
+ target.addEventListener("touchend", checkTarget);
+
+ sendTouchEvent(cwu, "touchstart", e, 0);
+
+ e.touches[0].page.x++;
+ sendTouchEvent(cwu, "touchmove", e, 0);
+ sendTouchEvent(cwu, "touchend", e, 0);
+
+ target.removeEventListener("touchstart", removeTarget);
+ target.removeEventListener("touchmove", checkTarget);
+ target.removeEventListener("touchend", checkTarget);
+
+ is(touchEvents, 2, "Check target was called twice");
+
+ nextTest();
+}
+
+function testNAC() {
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target = document.getElementById("testTarget3");
+ let bcr = target.getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ page: {x: Math.round(bcr.left + bcr.width/2),
+ y: Math.round(bcr.top + bcr.height/2)},
+ target
+ });
+ let event = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+
+ // test touchstart event fires correctly
+ var checkFunction = checkEvent(event);
+ window.addEventListener("touchstart", checkFunction);
+ sendTouchEvent(cwu, "touchstart", event, 0);
+ window.removeEventListener("touchstart", checkFunction);
+
+ sendTouchEvent(cwu, "touchend", event, 0);
+
+ nextTest();
+}
+
+function doTest() {
+ tests.push(testSingleTouch);
+ tests.push(testSingleTouch2);
+ tests.push(testMultiTouch);
+ tests.push(testPreventDefault);
+ tests.push(testTouchChanged);
+ tests.push(testRemovingElement);
+ tests.push(testNAC);
+
+ tests.push(function() {
+ SimpleTest.finish();
+ });
+
+ nextTest();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+</script>
+</pre>
+<div id="parent">
+ <span id="testTarget" style="padding: 5px; border: 1px solid black;">testTarget</span>
+ <span id="testTarget2" style="padding: 5px; border: 1px solid blue;">testTarget</span>
+ <input type="text" id="testTarget3">
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug605242.html b/dom/events/test/test_bug605242.html
new file mode 100644
index 0000000000..732501f558
--- /dev/null
+++ b/dom/events/test/test_bug605242.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=605242
+-->
+<head>
+ <title>Test for Bug 605242</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="setTimeout('runTest()', 0)">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=605242">Mozilla Bug 605242</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 605242 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var utils = SpecialPowers.getDOMWindowUtils(window);
+function sendMouseDown(el) {
+ var rect = el.getBoundingClientRect();
+ utils.sendMouseEvent('mousedown', rect.left + 5, rect.top + 5, 0, 1, 0);
+}
+
+function sendMouseUp(el) {
+ var rect = el.getBoundingClientRect();
+ utils.sendMouseEvent('mouseup', rect.left + 5, rect.top + 5, 0, 1, 0);
+}
+
+function runTest() {
+ var b = document.getElementById("testbutton");
+ sendMouseDown(b);
+ var l = document.querySelectorAll(":active");
+
+ var contains = false;
+ for (var i = 0; i < l.length; ++i) {
+ if (l[i] == b) {
+ contains = true;
+ }
+ }
+
+ ok(contains, "Wrong active content! \n");
+ sendMouseUp(b);
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+<button id="testbutton">A button</button>
+<pre id="log">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug607464.html b/dom/events/test/test_bug607464.html
new file mode 100644
index 0000000000..d67853339a
--- /dev/null
+++ b/dom/events/test/test_bug607464.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=607464
+-->
+<head>
+ <title>Test for Bug 607464</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=607464">Mozilla Bug 607464</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/**
+ * Test for Bug 607464:
+ * Pixel scrolling shouldn't scroll smoothly, even if general.smoothScroll is on.
+ **/
+
+function scrollDown150PxWithPixelScrolling(scrollbox) {
+ var win = scrollbox.ownerDocument.defaultView;
+ let event = {
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaY: 30.0,
+ lineOrPageDeltaY: 1
+ };
+ // A pixel scroll with lineOrPageDeltaY.
+ synthesizeWheel(scrollbox, 10, 10, event, win);
+ // then 4 pixel scrolls without lineOrPageDeltaY.
+ event.lineOrPageDeltaY = 0;
+ for (let i = 0; i < 4; ++i) {
+ synthesizeWheel(scrollbox, 10, 10, event, win);
+ }
+
+ // Note: the line scroll shouldn't have any effect because it has
+ // hasPixels = true set on it. We send it to emulate normal
+ // behavior.
+}
+
+function runTest() {
+ var win = open('bug607464.html', '_blank', 'width=300,height=300');
+ SimpleTest.waitForFocus(function () {
+ var scrollbox = win.document.getElementById("scrollbox");
+ let scrollTopBefore = scrollbox.scrollTop;
+
+ win.addEventListener("scroll", function(e) {
+ is(scrollbox.scrollTop % 30, 0,
+ "Pixel scrolling should happen instantly, not smoothly. The " +
+ "scroll position " + scrollbox.scrollTop + " in this sequence of wheel " +
+ "events should be a multiple of 30.");
+ if (scrollbox.scrollTop == 150) {
+ win.close();
+ SimpleTest.finish();
+ }
+ }, true);
+
+ flushApzRepaints(function() {
+ scrollDown150PxWithPixelScrolling(scrollbox);
+ }, win);
+ }, win);
+}
+
+window.onload = function() {
+ SpecialPowers.pushPrefEnv({
+ "set":[["general.smoothScroll", true],
+ ["mousewheel.acceleration.start", -1],
+ ["mousewheel.system_scroll_override_on_root_content.enabled", false]]}, runTest);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.testInChaosMode();
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug613634.html b/dom/events/test/test_bug613634.html
new file mode 100644
index 0000000000..18205d23df
--- /dev/null
+++ b/dom/events/test/test_bug613634.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=613634
+-->
+<head>
+ <title>Test for Bug 613634</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613634">Mozilla Bug 613634</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 613634 **/
+
+var eventCount = 0;
+function l(e) {
+ if (e.eventPhase != Event.CAPTURING_PHASE) {
+ ++eventCount;
+ } else {
+ ok(false, "Listener shouldn't be called!");
+ }
+}
+
+var d1 = document.createElement("div");
+var d2 = document.createElement("div");
+
+d1.appendChild(d2);
+
+var x = new XMLHttpRequest();
+
+try {
+d1.addEventListener("foo", l);
+document.addEventListener("foo", l);
+window.addEventListener("foo", l);
+x.addEventListener("foo", l);
+} catch(ex) {
+ ok(false, "Shouldn't throw " + ex);
+}
+
+var ev = document.createEvent("Event");
+ev.initEvent("foo", true, true);
+d2.dispatchEvent(ev);
+is(eventCount, 1, "Event listener should have been called!");
+
+ev = document.createEvent("Event");
+ev.initEvent("foo", false, false);
+d2.dispatchEvent(ev);
+is(eventCount, 1, "Event listener shouldn't have been called!");
+
+d1.removeEventListener("foo", l);
+ev = document.createEvent("Event");
+ev.initEvent("foo", true, true);
+d2.dispatchEvent(ev);
+is(eventCount, 1, "Event listener shouldn't have been called!");
+
+
+ev = document.createEvent("Event");
+ev.initEvent("foo", true, true);
+document.body.dispatchEvent(ev);
+is(eventCount, 3, "Event listener should have been called on document and window!");
+
+document.removeEventListener("foo", l);
+window.removeEventListener("foo", l);
+ev = document.createEvent("Event");
+ev.initEvent("foo", true, true);
+document.body.dispatchEvent(ev);
+is(eventCount, 3, "Event listener shouldn't have been called on document and window!");
+
+ev = document.createEvent("Event");
+ev.initEvent("foo", true, true);
+x.dispatchEvent(ev);
+is(eventCount, 4, "Event listener should have been called on XMLHttpRequest!");
+
+x.removeEventListener("foo", l);
+ev = document.createEvent("Event");
+ev.initEvent("foo", true, true);
+x.dispatchEvent(ev);
+is(eventCount, 4, "Event listener shouldn't have been called on XMLHttpRequest!");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug615597.html b/dom/events/test/test_bug615597.html
new file mode 100644
index 0000000000..ddca4a6869
--- /dev/null
+++ b/dom/events/test/test_bug615597.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=615597
+-->
+<head>
+ <title>Test for Bug 615597</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=615597">Mozilla Bug 615597</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 615597 **/
+
+window.addEventListener("deviceorientation", function(event) {
+ is(event.alpha, 1.5);
+ is(event.beta, 2.25);
+ is(event.gamma, 3.667);
+ is(event.absolute, true);
+}, true);
+
+var event = DeviceOrientationEvent;
+ok(!!event, "Should have seen DeviceOrientationEvent!");
+
+event = document.createEvent("DeviceOrientationEvent");
+event.initDeviceOrientationEvent('deviceorientation', true, true, 1.5, 2.25, 3.667, true);
+window.dispatchEvent(event);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug617528.xhtml b/dom/events/test/test_bug617528.xhtml
new file mode 100644
index 0000000000..2d2e0e0060
--- /dev/null
+++ b/dom/events/test/test_bug617528.xhtml
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=617528
+-->
+<window title="Mozilla Bug 617528"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=617528"
+ target="_blank">Mozilla Bug 617528</a>
+ </body>
+
+ <script type="application/javascript"><![CDATA[
+ const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
+ var _window;
+ var browser;
+
+ function start() {
+ _window = window.browsingContext.topChromeWindow.open("window_bug617528.xhtml", "_new", "chrome");
+ _window.addEventListener("load", onLoad, false);
+ }
+
+ function onLoad() {
+ _window.removeEventListener("load", onLoad, false);
+
+ browser = _window.document.getElementById("browser");
+ browser.addEventListener("pageshow", onPageShow, false);
+
+ var uri='data:text/html,\
+<html>\
+ <body>\
+ <div oncontextmenu="event.preventDefault()">\
+ <input id="node" type="text" value="Click here"></input>\
+ </div>\
+ </body>\
+</html>';
+ BrowserTestUtils.loadURI(browser, uri);
+ }
+
+ function onPageShow() {
+ browser.removeEventListener("pageshow", onPageShow, true);
+ SimpleTest.executeSoon(doTest);
+ }
+
+ function onContextMenu1(event) {
+ is(event.defaultPrevented, true,
+ "expected event.defaultPrevented to be true (1)");
+ is(event.target.localName, "input",
+ "expected event.target.localName to be 'input' (1)");
+ is(event.originalTarget.localName, "div",
+ "expected event.originalTarget.localName to be 'div' (1)");
+ }
+
+ function onContextMenu2(event) {
+ is(event.defaultPrevented, false,
+ "expected event.defaultPrevented to be false (2)");
+ is(event.target.localName, "input",
+ "expected event.target.localName to be 'input' (2)");
+ is(event.originalTarget.localName, "div",
+ "expected event.originalTarget.localName to be 'div' (2)");
+ }
+
+ function doTest() {
+ var win = browser.contentWindow;
+ win.focus();
+ var node = win.document.getElementById("node");
+ var rect = node.getBoundingClientRect();
+ var left = rect.left + rect.width / 2;
+ var top = rect.top + rect.height / 2;
+
+ var wu = win.windowUtils;
+
+ browser.addEventListener("contextmenu", onContextMenu1, false);
+ wu.sendMouseEvent("contextmenu", left, top, 2, 1, 0);
+ browser.removeEventListener("contextmenu", onContextMenu1, false);
+
+ browser.addEventListener("contextmenu", onContextMenu2, false);
+ var shiftMask = Event.SHIFT_MASK;
+ wu.sendMouseEvent("contextmenu", left, top, 2, 1, shiftMask);
+ browser.removeEventListener("contextmenu", onContextMenu2, false);
+
+ _window.close();
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(start);
+ SimpleTest.waitForExplicitFinish();
+ ]]></script>
+</window>
diff --git a/dom/events/test/test_bug624127.html b/dom/events/test/test_bug624127.html
new file mode 100644
index 0000000000..7099f9f936
--- /dev/null
+++ b/dom/events/test/test_bug624127.html
@@ -0,0 +1,35 @@
+<html>
+<head>
+ <title>Test for Bug 624127</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="setTimeout('runTest()', 0)">
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+ synthesizeMouse($("text"), 2, 2, { type: "mousedown" });
+ synthesizeMouse(frames[0].document.body, 2, 2, { type: "mouseup" }, frames[0]);
+ synthesizeMouse($("text2"), 50, 8, { type: "mousemove" });
+
+ is(window.getSelection().toString(), "", "no selection made");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+
+<p id="text">Normal text</p>
+<iframe srcdoc="text in iframe"></iframe>
+<p id="text2">Normal text</p>
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug635465.html b/dom/events/test/test_bug635465.html
new file mode 100644
index 0000000000..1e1bf7330f
--- /dev/null
+++ b/dom/events/test/test_bug635465.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=635465
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 635465</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style type="text/css">
+ #item {
+ position: relative;
+ }
+ .s-menu-section-submenu {
+ position: absolute;
+ display: none;
+ }
+ .open .s-menu-section-submenu {
+ display: block;
+ }
+</style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635465">Mozilla Bug 635465</a>
+<div id="display">
+ <div class="item" id="item"
+ onmouseover="showSubmenu(event)" onmouseout="hideSubmenu(event)">
+ <a href="#" id="firsthover">Hover me</a>
+ <div class="s-menu-section-submenu" id="menu">
+ <a href="#" id="secondhover">Now hover me</a>
+ </div>
+ </div>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 635465 **/
+function showSubmenu(event) {
+ var item = document.getElementById('item');
+
+ var width = item.offsetWidth; // IT WORKS IF YOU REMOVE THIS LINE
+
+ item.className='open';
+}
+
+function hideSubmenu(event) {
+ document.getElementById('item').className='';
+}
+
+SimpleTest.waitForExplicitFinish();
+
+function executeTests() {
+ // First flush out layout of firsthover
+ ok($("firsthover").getBoundingClientRect().height > 0,
+ "Should have a nonzero height before hover");
+
+ // Now trigger a mouseover on firsthover
+ synthesizeMouseAtCenter($("firsthover"), { type: "mousemove" });
+
+ ok($("secondhover").getBoundingClientRect().height > 0,
+ "Should have a nonzero height for submenu after hover");
+
+ // Now determine where secondhover is hanging out
+ var rect = $("secondhover").getBoundingClientRect();
+ synthesizeMouseAtCenter($("secondhover"), { type: "mousemove" });
+
+ // And another mouseover one pixel to the right of where the center used to be
+ synthesizeMouseAtPoint(rect.left + rect.width/2 + 1,
+ rect.top + rect.height/2,
+ { type: "mousemove" });
+
+ ok($("secondhover").getBoundingClientRect().height > 0,
+ "Should have a nonzero height for submenu after second hover");
+
+ // And check computed display of the menu
+ is(getComputedStyle($("menu"), "").display, "block", "Should have block display");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(executeTests);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug641477.html b/dom/events/test/test_bug641477.html
new file mode 100644
index 0000000000..b669c3145b
--- /dev/null
+++ b/dom/events/test/test_bug641477.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=641477
+-->
+<head>
+ <title>Test for Bug 641477</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=641477">Mozilla Bug 641477</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 641477 **/
+
+var didThrow = false;
+
+var e = document.createEvent("Event");
+try {
+ is(e.type, "", "Event type should be empty string before initialization");
+ document.dispatchEvent(e);
+} catch(ex) {
+ didThrow = (ex.name == "InvalidStateError" && ex.code == DOMException.INVALID_STATE_ERR);
+}
+
+ok(didThrow, "Should have thrown InvalidStateError!");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug648573.html b/dom/events/test/test_bug648573.html
new file mode 100644
index 0000000000..11348349ba
--- /dev/null
+++ b/dom/events/test/test_bug648573.html
@@ -0,0 +1,120 @@
+<!-- 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/. -->
+
+<!DOCTYPE html>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=648573
+ -->
+ <head>
+ <title>Test for Bug 648573</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=648573">Mozilla Bug 648573</a>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+
+ </div>
+ <pre id="test">
+ <script type="application/javascript">
+
+ /** Test for Bug 648573 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function runTest() {
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+ var win = iframe.contentWindow;
+ var doc = iframe.contentDocument;
+
+ var utils = SpecialPowers.getDOMWindowUtils(win);
+
+ ok("createTouch" in doc, "Should have createTouch function");
+ ok("createTouchList" in doc, "Should have createTouchList function");
+ ok(doc.createEvent("touchevent"), "Should be able to create TouchEvent objects");
+
+ var t1 = doc.createTouch(win, doc, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+ is(t1.target, doc, "Wrong target");
+ is(t1.identifier, 1, "Wrong identifier");
+ is(t1.pageX, 2, "Wrong pageX");
+ is(t1.pageY, 3, "Wrong pageY");
+ is(t1.screenX, 4, "Wrong screenX");
+ is(t1.screenY, 5, "Wrong screenY");
+ is(t1.clientX, 6, "Wrong clientX");
+ is(t1.clientY, 7, "Wrong clientY");
+ is(t1.radiusX, 8, "Wrong radiusX");
+ is(t1.radiusY, 9, "Wrong radiusY");
+ is(t1.rotationAngle, 10, "Wrong rotationAngle");
+ is(t1.force, 11, "Wrong force");
+
+ var t2 = doc.createTouch();
+
+ var l1 = doc.createTouchList(t1);
+ is(l1.length, 1, "Wrong length");
+ is(l1.item(0), t1, "Wront item (1)");
+ is(l1[0], t1, "Wront item (2)");
+
+ var l2 = doc.createTouchList([t1, t2]);
+ is(l2.length, 2, "Wrong length");
+ is(l2.item(0), t1, "Wront item (3)");
+ is(l2.item(1), t2, "Wront item (4)");
+ is(l2[0], t1, "Wront item (5)");
+ is(l2[1], t2, "Wront item (6)");
+
+ var l3 = doc.createTouchList();
+
+ var e = doc.createEvent("touchevent");
+ e.initTouchEvent("touchmove", true, true, win, 0, true, true, true, true,
+ l1, l2, l3);
+ is(e.touches, l1, "Wrong list (1)");
+ is(e.targetTouches, l2, "Wrong list (2)");
+ is(e.changedTouches, l3, "Wrong list (3)");
+ ok(e.altKey, "Alt should be true");
+ ok(e.metaKey, "Meta should be true");
+ ok(e.ctrlKey, "Ctrl should be true");
+ ok(e.shiftKey, "Shift should be true");
+
+
+ var events =
+ ["touchstart",
+ "touchend",
+ "touchmove",
+ "touchcancel"];
+
+ function runEventTest(type) {
+ var event = doc.createEvent("touchevent");
+ event.initTouchEvent(type, true, true, win, 0, true, true, true, true,
+ l1, l2, l3);
+ var t = doc.createElement("div");
+ // Testing target.onFoo;
+ var didCall = false;
+ t["on" + type] = function (evt) {
+ is(evt, event, "Wrong event");
+ evt.target.didCall = true;
+ }
+ t.dispatchEvent(event);
+ ok(t.didCall, "Should have called the listener(1)");
+
+ // Testing <element onFoo="">
+ t = doc.createElement("div");
+ t.setAttribute("on" + type, "this.didCall = true;");
+ t.dispatchEvent(event);
+ ok(t.didCall, "Should have called the listener(2)");
+ }
+
+ for (var i = 0; i < events.length; ++i) {
+ runEventTest(events[i]);
+ }
+
+ SimpleTest.finish();
+ }
+
+ SpecialPowers.pushPrefEnv(
+ {"set": [["dom.w3c_touch_events.legacy_apis.enabled", true]]}, runTest);
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/events/test/test_bug650493.html b/dom/events/test/test_bug650493.html
new file mode 100644
index 0000000000..a830c688fd
--- /dev/null
+++ b/dom/events/test/test_bug650493.html
@@ -0,0 +1,215 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650493
+-->
+<head>
+ <title>Test for Bug 650493</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650493">Mozilla Bug 650493</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function getNodes() {
+ var walker = document.createTreeWalker($('content'), NodeFilter.SHOW_ALL, null);
+ var nodes = [];
+ do {
+ nodes.push(walker.currentNode);
+ } while(walker.nextNode());
+
+ return nodes;
+}
+
+function check() {
+ var current = getNodes();
+ is(nodes.length, current.length, "length after " + testName);
+ nodes.forEach(function(val, index) {
+ ok(current.indexOf(val) > -1, "nodes[" + index + "] (" + val + ") shouldn't exist after " + testName);
+ });
+}
+
+var nodes = getNodes();
+var testName = "empty";
+var mutateCount = 0;
+
+check();
+
+// Set up listeners
+root = $('content');
+root.addEventListener("DOMNodeInserted", function(e) {
+ mutateCount++;
+ is(e.isTrusted, true, "untrusted mutation event");
+ var w = document.createTreeWalker(e.target, NodeFilter.SHOW_ALL, null);
+ do {
+ is(nodes.indexOf(w.currentNode), -1, "already have inserted node (" + w.currentNode + ") when " + testName);
+ nodes.push(w.currentNode);
+ } while(w.nextNode());
+});
+root.addEventListener("DOMNodeRemoved", function(e) {
+ mutateCount++;
+ is(e.isTrusted, true, "untrusted mutation event");
+ var w = document.createTreeWalker(e.target, NodeFilter.SHOW_ALL, null);
+ do {
+ var index = nodes.indexOf(w.currentNode);
+ ok(index != -1, "missing removed node (" + w.currentNode + ") when " + testName);
+ nodes.splice(index, 1);
+ } while(w.nextNode());
+});
+
+testName = "text-only innerHTML";
+root.innerHTML = "hello world";
+check();
+
+testName = "innerHTML with <b>";
+root.innerHTML = "<b>bold</b> world";
+check();
+
+testName = "complex innerHTML";
+root.innerHTML = "<b>b<span>old</span></b> <strong>world";
+check();
+
+testName = "replacing using .textContent";
+root.textContent = "i'm just a plain text minding my own business";
+check();
+
+testName = "clearing using .textContent";
+root.textContent = "";
+check();
+
+testName = "inserting using .textContent";
+root.textContent = "i'm new text!!";
+check();
+
+testName = "inserting using .textContent";
+root.textContent = "i'm new text!!";
+check();
+
+testName = "preparing to normalize";
+root.innerHTML = "<u><b>foo</b></u> ";
+var u = root.firstChild;
+is(u.nodeName, "U", "got the right node");
+var b = u.firstChild;
+is(b.nodeName, "B", "got the right node");
+b.insertBefore(document.createTextNode(""), b.firstChild);
+b.insertBefore(document.createTextNode(""), b.firstChild);
+b.appendChild(document.createTextNode(""));
+b.appendChild(document.createTextNode("hello"));
+b.appendChild(document.createTextNode("world"));
+u.appendChild(document.createTextNode("foo"));
+u.appendChild(document.createTextNode(""));
+u.appendChild(document.createTextNode("bar"));
+check();
+
+testName = "normalizing";
+root.normalize();
+check();
+
+testName = "self replace firstChild";
+mutateCount = 0;
+root.replaceChild(root.firstChild, root.firstChild);
+check();
+is(mutateCount, 2, "should remove and reinsert " + testName);
+
+testName = "self replace second child";
+mutateCount = 0;
+root.replaceChild(root.firstChild.nextSibling, root.firstChild.nextSibling);
+check();
+is(mutateCount, 2, "should remove and reinsert " + testName);
+
+testName = "self replace lastChild";
+mutateCount = 0;
+root.replaceChild(root.lastChild, root.lastChild);
+check();
+is(mutateCount, 2, "should remove and reinsert " + testName);
+
+testName = "self insertBefore firstChild";
+mutateCount = 0;
+root.insertBefore(root.firstChild, root.firstChild);
+check();
+is(mutateCount, 2, "should remove and reinsert " + testName);
+
+testName = "self insertBefore second child";
+mutateCount = 0;
+root.insertBefore(root.firstChild.nextSibling, root.firstChild.nextSibling);
+check();
+is(mutateCount, 2, "should remove and reinsert " + testName);
+
+testName = "self insertBefore lastChild";
+mutateCount = 0;
+root.insertBefore(root.lastChild, root.lastChild);
+check();
+is(mutateCount, 2, "should remove and reinsert " + testName);
+
+testName = "appendChild last";
+mutateCount = 0;
+root.appendChild(root.lastChild);
+check();
+is(mutateCount, 2, "should remove and reinsert " + testName);
+
+testName = "prepare script/style";
+script = document.createElement("script");
+script.appendChild(document.createTextNode("void(0);"));
+root.appendChild(script);
+style = document.createElement("style");
+root.appendChild(style);
+check();
+
+testName = "set something in script";
+script.text = "something";
+check();
+
+testName = "set something in style";
+style.innerHTML = "something { dislay: none; }";
+check();
+
+testName = "moving style";
+root.insertBefore(style, root.firstChild);
+check();
+
+testName = "replacing script";
+root.replaceChild(b, script);
+check();
+
+testName = "doc-fragment insert in the middle";
+frag = document.createDocumentFragment();
+frag.addEventListener("DOMNodeRemoved", function(e) {
+ var index = children.indexOf(e.target);
+ ok(index != -1, "unknown child removed from fragment");
+ children.splice(index, 1);
+});
+var children = [];
+children.push(document.createTextNode("foo"));
+children.push(document.createTextNode("bar"));
+children.push(document.createElement("span"));
+children.push(document.createElement("b"));
+children[2].appendChild(document.createElement("i"));
+children.forEach(function(child) { frag.appendChild(child); });
+ok(root.firstChild, "need to have children in order to test inserting before end");
+root.replaceChild(frag, root.firstChild);
+check();
+is(children.length, 0, "should have received DOMNodeRemoved for all frag children when inserting");
+is(frag.childNodes.length, 0, "fragment should be empty when inserting");
+
+testName = "doc-fragment append at the end";
+children.push(document.createTextNode("foo"));
+children.push(document.createTextNode("bar"));
+children.push(document.createElement("span"));
+children.push(document.createElement("b"));
+children[2].appendChild(document.createElement("i"));
+children.forEach(function(child) { frag.appendChild(child); });
+root.appendChild(frag);
+check();
+is(children.length, 0, "should have received DOMNodeRemoved for all frag children when appending");
+is(frag.childNodes.length, 0, "fragment should be empty when appending");
+
+</script>
+</body>
+</html>
+
diff --git a/dom/events/test/test_bug656379-1.html b/dom/events/test/test_bug656379-1.html
new file mode 100644
index 0000000000..9eee769c04
--- /dev/null
+++ b/dom/events/test/test_bug656379-1.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=656379
+-->
+<head>
+ <title>Test for Bug 656379</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 656379 **/
+SimpleTest.waitForExplicitFinish();
+var subwindow = window.open("./bug656379-1.html", "bug656379", "width=800,height=1000");
+
+function finishTests() {
+ subwindow.close();
+ SimpleTest.finish();
+}
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug656379-2.html b/dom/events/test/test_bug656379-2.html
new file mode 100644
index 0000000000..b7dd47bbc3
--- /dev/null
+++ b/dom/events/test/test_bug656379-2.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=656379
+-->
+<head>
+ <title>Test for Bug 656379</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ input[type="button"]:hover { color: green; }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=656379">Mozilla Bug 656379</a>
+<p id="display">
+ <label for="button1" id="label1">Label 1</label>
+ <input type="button" id="button1" value="Button 1">
+ <label>
+ <span id="label2">Label 2</span>
+ <input type="button" id="button2" value="Button 2">
+ </label>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+function log(aEvent) {
+ function getPath() {
+ if (!aEvent.target) {
+ return "(null)";
+ }
+ function getNodeName(aNode) {
+ if (aNode.id) {
+ return `${aNode.nodeName}#${aNode.id}`;
+ }
+ return aNode.nodeName;
+ }
+ let path = getNodeName(aEvent.target);
+ for (let parent = aEvent.target.parentElement;
+ parent && document.body != parent;
+ parent = parent.parentElement) {
+ path = `${getNodeName(parent)} > ${path}`;
+ }
+ return path;
+ }
+ info(`${aEvent.type} on ${getPath()}`);
+}
+
+window.addEventListener("mousemove", log, {capture: true});
+window.addEventListener("mouseenter", log, {capture: true});
+window.addEventListener("mouseleave", log, {capture: true});
+window.addEventListener("mouseover", log, {capture: true});
+window.addEventListener("mouseout", log, {capture: true});
+
+/** Test for Bug 656379 **/
+SimpleTest.waitForExplicitFinish();
+function* tests() {
+ info("Synthesizing mousemove on label1...");
+ synthesizeMouseAtCenter($("label1"), { type: "mousemove" });
+ yield undefined;
+ is($("button1").matches(":hover"), true,
+ "Button 1 should be hovered after mousemove over label1");
+ is($("label1").matches(":hover"), true,
+ "Label 1 should be hovered after mousemove over label1");
+ is($("button2").matches(":hover"), false,
+ "Button 2 should not be hovered after mousemove over label1");
+ is($("label2").matches(":hover"), false,
+ "Label 2 should not be hovered after mousemove over label1");
+ info("Synthesizing mousemove on button2...");
+ synthesizeMouseAtCenter($("button2"), { type: "mousemove" });
+ yield undefined;
+ is($("button1").matches(":hover"), false,
+ "Button 1 should not be hovered after mousemove over button2");
+ is($("label1").matches(":hover"), false,
+ "Label 1 should not be hovered after mousemove over button2");
+ is($("button2").matches(":hover"), true,
+ "Button 2 should be hovered after mousemove over button2");
+ is($("label2").matches(":hover"), false,
+ "Label 2 should not be hovered after mousemove over label2");
+ info("Synthesizing mousemove on label2...");
+ synthesizeMouseAtCenter($("label2"), { type: "mousemove" });
+ yield undefined;
+ is($("button1").matches(":hover"), false,
+ "Button 1 should not be hovered after mousemove over label2");
+ is($("label1").matches(":hover"), false,
+ "Label 1 should not be hovered after mousemove over label2");
+ is($("button2").matches(":hover"), true,
+ "Button 2 should be hovered after mousemove over label2");
+ is($("label2").matches(":hover"), true,
+ "Label 2 should be hovered after mousemove over label2");
+ SimpleTest.finish();
+}
+
+function executeTests() {
+ var testYielder = tests();
+ function execNext() {
+ let {done} = testYielder.next();
+ if (done) {
+ return;
+ }
+ SimpleTest.executeSoon(execNext);
+ }
+ execNext();
+}
+
+SimpleTest.waitForFocus(executeTests);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug656954.html b/dom/events/test/test_bug656954.html
new file mode 100644
index 0000000000..60f8cf4133
--- /dev/null
+++ b/dom/events/test/test_bug656954.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=656954
+-->
+<head>
+ <title>Test for Bug 656954</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=656954">Mozilla Bug 656954</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 656954 **/
+
+var e = document.createEvent("Event");
+is(e.defaultPrevented, false,
+ "After creating event defaultPrevented should be false");
+e.initEvent("foo", true, true);
+var el = document.createElement("div");
+el.addEventListener("foo",
+ function(evt) {
+ evt.preventDefault();
+ });
+el.dispatchEvent(e);
+is(e.defaultPrevented, true, "preventDefault() should have been called!");
+
+e = document.createEvent("Event");
+e.initEvent("foo", true, false);
+el.dispatchEvent(e);
+is(e.defaultPrevented, false, "preventDefault() should not have any effect!");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug659071.html b/dom/events/test/test_bug659071.html
new file mode 100644
index 0000000000..920d86da29
--- /dev/null
+++ b/dom/events/test/test_bug659071.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=659071
+-->
+<head>
+ <title>Test for Bug 659071</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=659071">Mozilla Bug 659071</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 659071 **/
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+var subWin = window.open("window_bug659071.html", "_blank",
+ "width=500,height=500");
+
+function finish()
+{
+ subWin.close();
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug659350.html b/dom/events/test/test_bug659350.html
new file mode 100644
index 0000000000..f4d64d1f35
--- /dev/null
+++ b/dom/events/test/test_bug659350.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=659350
+-->
+<head>
+ <title>Test for Bug 659350</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=659350">Mozilla Bug 659350</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 659350 **/
+function testIn(eventName, obj, objName, expected) {
+ is(eventName in obj, expected, "'" + eventName + "' shuld be in " + objName);
+}
+
+var div = document.createElement("div");
+
+// Forwarded events
+testIn("onscroll", window, "window", true);
+testIn("onscroll", document.body, "body", true);
+testIn("onscroll", div, "div", true);
+// Window events
+testIn("onpopstate", window, "window", true);
+testIn("onpopstate", document.body, "body", true);
+testIn("onpopstate", div, "div", false);
+// Non-idl events
+testIn("onopen", window, "window", false);
+testIn("onopen", document.body, "body", false);
+testIn("onopen", div, "div", false);
+
+function f() {}
+function g() {}
+
+// Basic sanity of interaction between the IDL and content attributes
+div.onload = f;
+is(div.onload, f, "Should have 'f' as div's onload");
+div.setAttribute("onload", "");
+isnot(div.onload, f, "Should not longer have 'f' as div's onload");
+is(div.onload.toString(), "function onload(event) {\n\n}",
+ "Should have wrapped empty string in a function");
+div.setAttribute("onload", "foopy();");
+is(div.onload.toString(), "function onload(event) {\nfoopy();\n}",
+ "Should have wrapped call in a function");
+div.removeAttribute("onload");
+is(div.onload, null, "Should have null onload now");
+
+// Test forwarding to window for both events that are window-specific and that
+// exist on all elements
+function testPropagationToWindow(eventName) {
+ is(window["on"+eventName], null, "Shouldn't have " + eventName + " stuff yet");
+ document.body["on"+eventName] = f;
+ is(window["on"+eventName], f,
+ "Setting on"+eventName+" on body should propagate to window");
+ document.createElement("body")["on"+eventName] = g;
+ is(window["on"+eventName], g,
+ "Setting on"+eventName+" on body not in document should propagate to window");
+ document.createElement("frameset")["on"+eventName] = f;
+ is(window["on"+eventName], f,
+ "Setting on"+eventName+" on frameset not in document should propagate to window");
+
+ document.body.setAttribute("on"+eventName, eventName);
+ is(window["on"+eventName].toString(),
+ "function on"+eventName+"(event) {\n"+eventName+"\n}",
+ "Setting on"+eventName+"attribute on body should propagate to window");
+ document.createElement("body").setAttribute("on"+eventName, eventName+"2");
+ is(window["on"+eventName].toString(),
+ "function on"+eventName+"(event) {\n"+eventName+"2\n}",
+ "Setting on"+eventName+"attribute on body outside the document should propagate to window");
+}
+
+testPropagationToWindow("popstate");
+testPropagationToWindow("scroll");
+
+// Test |this| and scoping
+var called;
+div.onscroll = function(event) {
+ is(this, div, "This should be div when invoking event listener");
+ is(event, ev, "Event argument should be the event that was dispatched");
+ called = true;
+}
+var ev = document.createEvent("Events");
+ev.initEvent("scroll", true, true);
+called = false;
+div.dispatchEvent(ev);
+is(called, true, "Event listener set via on* property not called");
+
+div.foopy = "Found me";
+document.foopy = "Didn't find me";
+document.foopy2 = "Found me";
+div.setAttribute("onscroll",
+ "is(this, div, 'This should be div when invoking via attribute');\
+ is(foopy, 'Found me', 'div should be on the scope chain when invoking handler compiled from content attribute');\
+ is(foopy2, 'Found me', 'document should be on the scope chain when invking handler compiled from content attribute');\
+ is(event, ev, 'Event argument should be the event that was dispatched');\
+ called = true;");
+called = false;
+div.dispatchEvent(ev);
+is(called, true, "Event listener set via on* attribute not called");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug662678.html b/dom/events/test/test_bug662678.html
new file mode 100644
index 0000000000..22fe8e75a3
--- /dev/null
+++ b/dom/events/test/test_bug662678.html
@@ -0,0 +1,153 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=662678
+-->
+<head>
+ <title>Test for Bug 662678</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=662678">Mozilla Bug 662678</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 662678 **/
+SimpleTest.waitForExplicitFinish();
+
+var checkMotion = function(event) {
+ window.removeEventListener("devicemotion", checkMotion, true);
+
+ is(event.acceleration.x, 1.5, "acceleration.x");
+ is(event.acceleration.y, 2.5, "acceleration.y");
+ is(event.acceleration.z, 3.5, "acceleration.z");
+ is(event.accelerationIncludingGravity.x, 4.5, "accelerationIncludingGravity.x");
+ is(event.accelerationIncludingGravity.y, 5.5, "accelerationIncludingGravity.y");
+ is(event.accelerationIncludingGravity.z, 6.5, "accelerationIncludingGravity.z");
+ is(event.rotationRate.alpha, 7.5, "rotationRate.alpha");
+ is(event.rotationRate.beta, 8.5, "rotationRate.beta");
+ is(event.rotationRate.gamma, 9.5, "rotationRate.gamma");
+ is(event.interval, 0.5, "interval");
+
+ var e = document.createEvent("DeviceMotionEvent");
+ e.initDeviceMotionEvent('devicemotion', true, true,
+ null, null, null, null);
+ is(e.acceleration.x, null, "acceleration.x");
+ is(e.acceleration.y, null, "acceleration.y");
+ is(e.acceleration.z, null, "acceleration.z");
+ is(e.accelerationIncludingGravity.x, null, "accelerationIncludingGravity.x");
+ is(e.accelerationIncludingGravity.y, null, "accelerationIncludingGravity.y");
+ is(e.accelerationIncludingGravity.z, null, "accelerationIncludingGravity.z");
+ is(e.rotationRate.alpha, null, "rotationRate.alpha");
+ is(e.rotationRate.beta, null, "rotationRate.beta");
+ is(e.rotationRate.gamma, null, "rotationRate.gamma");
+ is(e.interval, null, "interval");
+
+ e.initDeviceMotionEvent('devicemotion', true, true,
+ {}, {}, {}, 0);
+ is(e.acceleration.x, null, "acceleration.x");
+ is(e.acceleration.y, null, "acceleration.y");
+ is(e.acceleration.z, null, "acceleration.z");
+ is(e.accelerationIncludingGravity.x, null, "accelerationIncludingGravity.x");
+ is(e.accelerationIncludingGravity.y, null, "accelerationIncludingGravity.y");
+ is(e.accelerationIncludingGravity.z, null, "accelerationIncludingGravity.z");
+ is(e.rotationRate.alpha, null, "rotationRate.alpha");
+ is(e.rotationRate.beta, null, "rotationRate.beta");
+ is(e.rotationRate.gamma, null, "rotationRate.gamma");
+ is(e.interval, 0, "interval");
+
+ window.addEventListener("devicemotion", checkMotionCtor, true);
+
+ event = new DeviceMotionEvent('devicemotion', {
+ bubbles: true, cancelable: true,
+ acceleration: {x:1.5,y:2.5,z:3.5},
+ accelerationIncludingGravity: {x:4.5,y:5.5,z:6.5},
+ rotationRate: {alpha:7.5,beta:8.5,gamma:9.5},
+ interval: 0.5
+ });
+ window.dispatchEvent(event);
+};
+
+var checkMotionCtor = function(event) {
+ window.removeEventListener("devicemotion", checkMotionCtor, true);
+
+ is(event.acceleration.x, 1.5, "acceleration.x");
+ is(event.acceleration.y, 2.5, "acceleration.y");
+ is(event.acceleration.z, 3.5, "acceleration.z");
+ is(event.accelerationIncludingGravity.x, 4.5, "accelerationIncludingGravity.x");
+ is(event.accelerationIncludingGravity.y, 5.5, "accelerationIncludingGravity.y");
+ is(event.accelerationIncludingGravity.z, 6.5, "accelerationIncludingGravity.z");
+ is(event.rotationRate.alpha, 7.5, "rotationRate.alpha");
+ is(event.rotationRate.beta, 8.5, "rotationRate.beta");
+ is(event.rotationRate.gamma, 9.5, "rotationRate.gamma");
+ is(event.interval, 0.5, "interval");
+
+ var e = new DeviceMotionEvent('devicemotion');
+ is(e.acceleration.x, null, "acceleration.x");
+ is(e.acceleration.y, null, "acceleration.y");
+ is(e.acceleration.z, null, "acceleration.z");
+ is(e.accelerationIncludingGravity.x, null, "accelerationIncludingGravity.x");
+ is(e.accelerationIncludingGravity.y, null, "accelerationIncludingGravity.y");
+ is(e.accelerationIncludingGravity.z, null, "accelerationIncludingGravity.z");
+ is(e.rotationRate.alpha, null, "rotationRate.alpha");
+ is(e.rotationRate.beta, null, "rotationRate.beta");
+ is(e.rotationRate.gamma, null, "rotationRate.gamma");
+ is(e.interval, null, "interval");
+
+ e = new DeviceMotionEvent('devicemotion', {
+ bubbles: true, cancelable: true,
+ acceleration: null, accelerationIncludingGravity: null,
+ rotationRate: null, interval: null
+ });
+ is(e.acceleration.x, null, "acceleration.x");
+ is(e.acceleration.y, null, "acceleration.y");
+ is(e.acceleration.z, null, "acceleration.z");
+ is(e.accelerationIncludingGravity.x, null, "accelerationIncludingGravity.x");
+ is(e.accelerationIncludingGravity.y, null, "accelerationIncludingGravity.y");
+ is(e.accelerationIncludingGravity.z, null, "accelerationIncludingGravity.z");
+ is(e.rotationRate.alpha, null, "rotationRate.alpha");
+ is(e.rotationRate.beta, null, "rotationRate.beta");
+ is(e.rotationRate.gamma, null, "rotationRate.gamma");
+ is(e.interval, null, "interval");
+
+ e = new DeviceMotionEvent('devicemotion', {
+ bubbles: true, cancelable: true,
+ acceleration: {}, accelerationIncludingGravity: {},
+ rotationRate: {}, interval: 0
+ });
+ is(e.acceleration.x, null, "acceleration.x");
+ is(e.acceleration.y, null, "acceleration.y");
+ is(e.acceleration.z, null, "acceleration.z");
+ is(e.accelerationIncludingGravity.x, null, "accelerationIncludingGravity.x");
+ is(e.accelerationIncludingGravity.y, null, "accelerationIncludingGravity.y");
+ is(e.accelerationIncludingGravity.z, null, "accelerationIncludingGravity.z");
+ is(e.rotationRate.alpha, null, "rotationRate.alpha");
+ is(e.rotationRate.beta, null, "rotationRate.beta");
+ is(e.rotationRate.gamma, null, "rotationRate.gamma");
+ is(e.interval, 0, "interval");
+
+ SimpleTest.finish();
+};
+
+window.addEventListener("devicemotion", checkMotion, true);
+
+var event = DeviceMotionEvent;
+ok(!!event, "Should have seen DeviceMotionEvent!");
+
+event = document.createEvent("DeviceMotionEvent");
+event.initDeviceMotionEvent('devicemotion', true, true,
+ {x:1.5,y:2.5,z:3.5},
+ {x:4.5,y:5.5,z:6.5},
+ {alpha:7.5,beta:8.5,gamma:9.5},
+ 0.5);
+window.dispatchEvent(event);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug667612.html b/dom/events/test/test_bug667612.html
new file mode 100644
index 0000000000..95e7f430de
--- /dev/null
+++ b/dom/events/test/test_bug667612.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=667612
+-->
+<head>
+ <title>Test for Bug 667612</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=667612">Mozilla Bug 667612</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+xhr = new XMLHttpRequest;
+w = new Worker("empty.js");
+window.addEventListener("load", null);
+document.addEventListener("load", null);
+document.body.addEventListener("load", null);
+xhr.addEventListener("load", null);
+w.addEventListener("load", null);
+window.addEventListener("load", undefined);
+document.addEventListener("load", undefined);
+document.body.addEventListener("load", undefined);
+xhr.addEventListener("load", undefined);
+w.addEventListener("load", undefined);
+
+ok(true, "didn't throw");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug667919-1.html b/dom/events/test/test_bug667919-1.html
new file mode 100644
index 0000000000..d4be92dafb
--- /dev/null
+++ b/dom/events/test/test_bug667919-1.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=615597
+-->
+<head>
+ <title>Test for Bug 615597</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=615597">Mozilla Bug 615597</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 615597 **/
+
+window.ondeviceorientation = function(event) {
+ is(event.alpha, 1.5);
+ is(event.beta, 2.25);
+ is(event.gamma, 3.667);
+ is(event.absolute, true);
+ SimpleTest.finish();
+};
+
+var event = DeviceOrientationEvent;
+ok(!!event, "Should have seen DeviceOrientationEvent!");
+
+event = document.createEvent("DeviceOrientationEvent");
+event.initDeviceOrientationEvent('deviceorientation', true, true, 1.5, 2.25, 3.667, true);
+window.dispatchEvent(event);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug679494.xhtml b/dom/events/test/test_bug679494.xhtml
new file mode 100644
index 0000000000..22bda7f6f3
--- /dev/null
+++ b/dom/events/test/test_bug679494.xhtml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=679494
+-->
+<window title="Mozilla Bug 679494" onload="doTest();"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=679494">Mozilla Bug 679494</a>
+ <p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="contentframe" src="http://mochi.test:8888/tests/dom/events/test/file_bug679494.html"></iframe>
+</div>
+</body>
+
+<script class="testbody" type="application/javascript"><![CDATA[
+
+/* Test for bug 679494 */
+function doTest() {
+ SimpleTest.waitForExplicitFinish();
+
+ var w = document.getElementById("contentframe").contentWindow;
+ w.addEventListener("message", function(e) {
+ is("test", e.data, "We got the data without a compartment mismatch assertion!");
+ SimpleTest.finish();
+ }, false);
+ w.postMessage("test", "*");
+}
+
+]]></script>
+
+</window>
diff --git a/dom/events/test/test_bug684208.html b/dom/events/test/test_bug684208.html
new file mode 100644
index 0000000000..7405c9cb5c
--- /dev/null
+++ b/dom/events/test/test_bug684208.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=684208
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 684208</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 684208 **/
+
+ function checkDispatchReturnValue(targetOrUndefined) {
+ var target = targetOrUndefined ? targetOrUndefined : self;
+ function createEvent() {
+ if ("MouseEvent" in this) {
+ return new MouseEvent("click", {cancelable: true});
+ }
+ return new Event("dummy", {cancelable: true});
+ }
+
+ function postSelfMessage(msg) {
+ try {
+ self.postMessage(msg);
+ } catch(ex) {
+ self.postMessage(msg, "*");
+ }
+ }
+
+ function passiveListener(e) {
+ e.target.removeEventListener(e.type, passiveListener);
+ }
+ var event = createEvent();
+ target.addEventListener(event.type, passiveListener);
+ postSelfMessage(target.dispatchEvent(event) == true);
+
+ function cancellingListener(e) {
+ e.target.removeEventListener(e.type, cancellingListener);
+ e.preventDefault();
+ }
+ event = createEvent();
+ target.addEventListener(event.type, cancellingListener);
+ postSelfMessage(target.dispatchEvent(event) == false);
+ }
+
+ function test() {
+ var expectedEvents = 6;
+ function messageHandler(e) {
+ ok(e.data, "All the dispatchEvent calls should pass.");
+ --expectedEvents;
+ if (!expectedEvents) {
+ window.onmessage = null;
+ window.worker.onmessage = null;
+ SimpleTest.finish();
+ }
+ }
+ window.onmessage = messageHandler;
+ checkDispatchReturnValue();
+ checkDispatchReturnValue(document.getElementById("link"));
+ window.worker =
+ new Worker(URL.createObjectURL(new Blob(["(" + checkDispatchReturnValue.toString() + ")();"])));
+ window.worker.onmessage = messageHandler;
+ }
+
+ SimpleTest.waitForExplicitFinish();
+
+ </script>
+</head>
+<body onload="test();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=684208">Mozilla Bug 684208</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<a id="link" href="#foo">foo</a>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug687787.html b/dom/events/test/test_bug687787.html
new file mode 100644
index 0000000000..6461ece7d4
--- /dev/null
+++ b/dom/events/test/test_bug687787.html
@@ -0,0 +1,616 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+-->
+<head>
+ <title>Test for Bug 687787</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=687787">Mozilla Bug 687787</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var eventStack = [];
+
+function _callback(e){
+ var event = {'type' : e.type, 'target' : e.target, 'relatedTarget' : e.relatedTarget }
+ eventStack.push(event);
+}
+
+function clearEventStack(){
+ eventStack = [];
+}
+
+window.addEventListener("focus", _callback, true);
+window.addEventListener("focusin", _callback, true);
+window.addEventListener("focusout", _callback, true);
+window.addEventListener("blur", _callback, true);
+
+function CompareEventToExpected(e, expected) {
+ if (expected == null || e == null)
+ return false;
+ if (e.type == expected.type && e.target == expected.target && e.relatedTarget == expected.relatedTarget)
+ return true;
+ return false;
+}
+
+function TestEventOrderNormal() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var input3 = document.createElement('input');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ input3.setAttribute('id', 'input3');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+ input3.setAttribute('type', 'text');
+
+ content.appendChild(input1);
+ content.appendChild(input2);
+ content.appendChild(input3);
+ content.style.display = 'block'
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focus',
+ 'target' : input2,
+ 'relatedTarget' : input1},
+ {'type' : 'focusin',
+ 'target' : input2,
+ 'relatedTarget' : input1},
+ {'type' : 'blur',
+ 'target' : input2,
+ 'relatedTarget' : input3},
+ {'type' : 'focusout',
+ 'target' : input2,
+ 'relatedTarget' : input3},
+ {'type' : 'focus',
+ 'target' : input3,
+ 'relatedTarget' : input2},
+ {'type' : 'focusin',
+ 'target' : input3,
+ 'relatedTarget' : input2},
+ ]
+
+ input1.focus();
+ clearEventStack();
+
+ input2.focus();
+ input3.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length ; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+function TestEventOrderNormalFiresAtRightTime() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var input3 = document.createElement('input');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ input3.setAttribute('id', 'input3');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+ input3.setAttribute('type', 'text');
+
+ input1.onblur = function(e)
+ {
+ ok(document.activeElement == document.body, 'input1: not focused when blur fires')
+ }
+
+ input1.addEventListener('focusout', function(e)
+ {
+ ok(document.activeElement == document.body, 'input1: not focused when focusout fires')
+ });
+
+ input2.onfocus = function(e)
+ {
+ ok(document.activeElement == input2, 'input2: focused when focus fires')
+ }
+
+ input2.addEventListener('focusin', function(e)
+ {
+ ok(document.activeElement == input2, 'input2: focused when focusin fires')
+ });
+
+ content.appendChild(input1);
+ content.appendChild(input2);
+ content.style.display = 'block'
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focus',
+ 'target' : input2,
+ 'relatedTarget' : input1},
+ {'type' : 'focusin',
+ 'target' : input2,
+ 'relatedTarget' : input1},
+ ]
+
+ input1.focus();
+ clearEventStack();
+
+ input2.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length ; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+function TestFocusOutRedirectsFocus() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var input3 = document.createElement('input');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ input3.setAttribute('id', 'input3');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+ input3.setAttribute('type', 'text');
+ input1.addEventListener('focusout', function () {
+ input3.focus();
+ });
+
+ content.appendChild(input1);
+ content.appendChild(input2);
+ content.appendChild(input3);
+ content.style.display = 'block'
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focus',
+ 'target' : input3,
+ 'relatedTarget' : null},
+ {'type' : 'focusin',
+ 'target' : input3,
+ 'relatedTarget' : null},
+ ]
+
+ input1.focus();
+ clearEventStack();
+ input2.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+function TestFocusInRedirectsFocus() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var input3 = document.createElement('input');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ input3.setAttribute('id', 'input3');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+ input3.setAttribute('type', 'text');
+ input2.addEventListener('focusin', function () {
+ input3.focus();
+ });
+
+ content.appendChild(input1);
+ content.appendChild(input2);
+ content.appendChild(input3);
+ content.style.display = 'block'
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focus',
+ 'target' : input2,
+ 'relatedTarget' : input1},
+ {'type' : 'focusin',
+ 'target' : input2,
+ 'relatedTarget' : input1},
+ {'type' : 'blur',
+ 'target' : input2,
+ 'relatedTarget' : input3},
+ {'type' : 'focusout',
+ 'target' : input2,
+ 'relatedTarget' : input3},
+ {'type' : 'focus',
+ 'target' : input3,
+ 'relatedTarget' : input2},
+ {'type' : 'focusin',
+ 'target' : input3,
+ 'relatedTarget' : input2},
+ ]
+
+ input1.focus();
+ clearEventStack();
+ input2.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+function TestBlurRedirectsFocus() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var input3 = document.createElement('input');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ input3.setAttribute('id', 'input3');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+ input3.setAttribute('type', 'text');
+ input1.onblur = function () {
+ input3.focus();
+ }
+
+ content.appendChild(input1);
+ content.appendChild(input2);
+ content.appendChild(input3);
+ content.style.display = 'block'
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focus',
+ 'target' : input3,
+ 'relatedTarget' : null},
+ {'type' : 'focusin',
+ 'target' : input3,
+ 'relatedTarget' : null},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ ]
+
+ input1.focus();
+ clearEventStack();
+ input2.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+function TestFocusRedirectsFocus() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var input3 = document.createElement('input');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ input3.setAttribute('id', 'input3');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+ input3.setAttribute('type', 'text');
+ input2.onfocus = function () {
+ input3.focus();
+ }
+
+ content.appendChild(input1);
+ content.appendChild(input2);
+ content.appendChild(input3);
+ content.style.display = 'block'
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focus',
+ 'target' : input2,
+ 'relatedTarget' : input1},
+ {'type' : 'blur',
+ 'target' : input2,
+ 'relatedTarget' : input3},
+ {'type' : 'focusout',
+ 'target' : input2,
+ 'relatedTarget' : input3},
+ {'type' : 'focus',
+ 'target' : input3,
+ 'relatedTarget' : input2},
+ {'type' : 'focusin',
+ 'target' : input3,
+ 'relatedTarget' : input2},
+ ]
+
+ input1.focus();
+ clearEventStack();
+ input2.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+function TestEventOrderDifferentDocument() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var iframe1 = document.createElement('iframe');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ iframe1.setAttribute('id', 'iframe1');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+
+ content.appendChild(input1);
+ content.appendChild(iframe1);
+ iframe1.contentDocument.body.appendChild(input2);
+ content.style.display = 'block'
+
+ iframe1.contentDocument.addEventListener("focus", _callback, true);
+ iframe1.contentDocument.addEventListener("focusin", _callback, true);
+ iframe1.contentDocument.addEventListener("focusout", _callback, true);
+ iframe1.contentDocument.addEventListener("blur", _callback, true);
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : null},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : null},
+ {'type' : 'blur',
+ 'target' : document,
+ 'relatedTarget' : null},
+ {'type' : 'blur',
+ 'target' : window,
+ 'relatedTarget' : null},
+ {'type' : 'focus',
+ 'target' : iframe1.contentDocument,
+ 'relatedTarget' : null},
+ {'type' : 'focus',
+ 'target' : input2,
+ 'relatedTarget' : null},
+ {'type' : 'focusin',
+ 'target' : input2,
+ 'relatedTarget' : null},
+ ]
+
+ input1.focus();
+ clearEventStack();
+ input2.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+
+function TestFocusOutMovesTarget() {
+
+ var input1 = document.createElement('input');
+ var input2 = document.createElement('input');
+ var iframe1 = document.createElement('iframe');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input2.setAttribute('id', 'input2');
+ iframe1.setAttribute('id', 'iframe1');
+ input1.setAttribute('type', 'text');
+ input2.setAttribute('type', 'text');
+
+ input1.addEventListener('focusout', function () {
+ iframe1.contentDocument.body.appendChild(input2);
+ });
+
+ content.appendChild(input1);
+ content.appendChild(input2);
+ content.appendChild(iframe1);
+ content.style.display = 'block'
+
+ iframe1.contentDocument.addEventListener("focus", _callback, true);
+ iframe1.contentDocument.addEventListener("focusin", _callback, true);
+ iframe1.contentDocument.addEventListener("focusout", _callback, true);
+ iframe1.contentDocument.addEventListener("blur", _callback, true);
+
+ let expectedEventOrder = [
+ {'type' : 'blur',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focusout',
+ 'target' : input1,
+ 'relatedTarget' : input2},
+ {'type' : 'focus',
+ 'target' : input2,
+ 'relatedTarget' : null},
+ {'type' : 'focusin',
+ 'target' : input2,
+ 'relatedTarget' : null},
+ ]
+
+ input1.focus();
+ clearEventStack();
+ input2.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+function TestBlurWindowAndRefocusInputOnlyFiresFocusInOnInput() {
+
+ var input1 = document.createElement('input');
+ var content = document.getElementById('content');
+
+ input1.setAttribute('id', 'input1');
+ input1.setAttribute('type', 'text');
+
+ content.appendChild(input1);
+
+ let expectedEventOrder = [
+ {'type' : 'focus',
+ 'target' : document,
+ 'relatedTarget' : null},
+ {'type' : 'focus',
+ 'target' : window,
+ 'relatedTarget' : null},
+ {'type' : 'focus',
+ 'target' : input1,
+ 'relatedTarget' : null},
+ {'type' : 'focusin',
+ 'target' : input1,
+ 'relatedTarget' : null},
+ ]
+
+ window.blur();
+ clearEventStack();
+ input1.focus();
+
+ for (var i = 0; i < expectedEventOrder.length || i < eventStack.length; i++) {
+ ok(CompareEventToExpected(expectedEventOrder[i], eventStack[i]), 'Normal event order is correct: Event ' + i + ': '
+ + 'Expected ('
+ + expectedEventOrder[i].type + ','
+ + (expectedEventOrder[i].target ? expectedEventOrder[i].target.id : null) + ','
+ + (expectedEventOrder[i].relatedTarget ? expectedEventOrder[i].relatedTarget.id : null) + '), '
+ + 'Actual ('
+ + eventStack[i].type + ','
+ + (eventStack[i].target ? eventStack[i].target.id : null) + ','
+ + (eventStack[i].relatedTarget ? eventStack[i].relatedTarget.id : null) + ')');
+ }
+
+ content.innerHTML = '';
+}
+
+TestEventOrderNormal();
+TestEventOrderNormalFiresAtRightTime();
+TestFocusOutRedirectsFocus();
+TestFocusInRedirectsFocus();
+TestBlurRedirectsFocus();
+TestFocusRedirectsFocus();
+TestFocusOutMovesTarget();
+TestEventOrderDifferentDocument();
+TestBlurWindowAndRefocusInputOnlyFiresFocusInOnInput();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug689564.html b/dom/events/test/test_bug689564.html
new file mode 100644
index 0000000000..7183e6169d
--- /dev/null
+++ b/dom/events/test/test_bug689564.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=689564
+-->
+<head>
+ <title>Test for Bug 689564</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=689564">Mozilla Bug 689564</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 689564 **/
+var div = document.createElement("div");
+div.setAttribute("onclick", "div");
+is(window.onclick, null, "div should not forward onclick");
+is(div.onclick.toString(), "function onclick(event) {\ndiv\n}",
+ "div should have an onclick handler");
+
+div.setAttribute("onscroll", "div");
+is(window.onscroll, null, "div should not forward onscroll");
+is(div.onscroll.toString(), "function onscroll(event) {\ndiv\n}",
+ "div should have an onscroll handler");
+
+div.setAttribute("onpopstate", "div");
+is(window.onpopstate, null, "div should not forward onpopstate");
+is("onpopstate" in div, false, "div should not have onpopstate handler");
+
+var body = document.createElement("body");
+body.setAttribute("onclick", "body");
+is(window.onclick, null, "body should not forward onclick");
+is(body.onclick.toString(), "function onclick(event) {\nbody\n}",
+ "body should have an onclick handler");
+body.setAttribute("onscroll", "body");
+is(window.onscroll.toString(), "function onscroll(event) {\nbody\n}",
+ "body should forward onscroll");
+body.setAttribute("onpopstate", "body");
+is(window.onpopstate.toString(), "function onpopstate(event) {\nbody\n}",
+ "body should forward onpopstate");
+
+var frameset = document.createElement("frameset");
+frameset.setAttribute("onclick", "frameset");
+is(window.onclick, null, "frameset should not forward onclick");
+is(frameset.onclick.toString(), "function onclick(event) {\nframeset\n}",
+ "frameset should have an onclick handler");
+frameset.setAttribute("onscroll", "frameset");
+is(window.onscroll.toString(), "function onscroll(event) {\nframeset\n}",
+ "frameset should forward onscroll");
+frameset.setAttribute("onpopstate", "frameset");
+is(window.onpopstate.toString(), "function onpopstate(event) {\nframeset\n}",
+ "frameset should forward onpopstate");
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug698929.html b/dom/events/test/test_bug698929.html
new file mode 100644
index 0000000000..d450ec8517
--- /dev/null
+++ b/dom/events/test/test_bug698929.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=698929
+-->
+<head>
+ <title>Test for Bug 698929</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=698929">Mozilla Bug 698929</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 698929 **/
+
+ var e = document.createEvent("Event");
+ e.initEvent("foo", true, true);
+ var c = 0;
+ var b = 0;
+ document.addEventListener("foo",
+ function() {
+ ++c;
+ });
+ document.body.addEventListener("foo", function(event) {
+ ++b;
+ event.stopImmediatePropagation();
+ });
+ document.body.addEventListener("foo", function(event) {
+ ++b;
+ });
+ document.body.dispatchEvent(e);
+ document.documentElement.dispatchEvent(e);
+ is(c, 1, "Listener in the document should have been called once.");
+ is(b, 1, "Listener in the body should have been called once.");
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug704423.html b/dom/events/test/test_bug704423.html
new file mode 100644
index 0000000000..30b1913d07
--- /dev/null
+++ b/dom/events/test/test_bug704423.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=704423
+-->
+<head>
+ <title>Test for Bug 704423</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704423">Mozilla Bug 704423</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 704423 **/
+
+function doTest()
+{
+ function handler(aEvent) {
+ aEvent.preventDefault();
+ ok(aEvent.defaultPrevented,
+ "mousemove event should be cancelable");
+ }
+ window.addEventListener("mousemove", handler, true);
+ synthesizeMouseAtCenter(document.body, { type: "mousemove" });
+ window.removeEventListener("mousemove", handler, true);
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(doTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug741666.html b/dom/events/test/test_bug741666.html
new file mode 100644
index 0000000000..bc2117577f
--- /dev/null
+++ b/dom/events/test/test_bug741666.html
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=741666
+-->
+<head>
+ <title>Test for Bug 741666</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741666">Mozilla Bug 741666</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+
+/** Test for Bug 306008 - Touch events with a reference held should retain their touch lists **/
+
+let tests = [], testTarget, parent;
+
+let touch = {
+ id: 0,
+ point: {x: 0, y: 0},
+ radius: {x: 0, y: 0},
+ rotation: 0,
+ force: 0.5,
+ target: null
+}
+
+function nextTest() {
+ if (tests.length)
+ SimpleTest.executeSoon(tests.shift());
+}
+
+function checkEvent(aFakeEvent, aTouches) {
+ return function(aEvent, aTrusted) {
+ is(aFakeEvent.ctrlKey, aEvent.ctrlKey, "Correct ctrlKey");
+ is(aFakeEvent.altKey, aEvent.altKey, "Correct altKey");
+ is(aFakeEvent.shiftKey, aEvent.shiftKey, "Correct shiftKey");
+ is(aFakeEvent.metaKey, aEvent.metaKey, "Correct metaKey");
+ is(aEvent.isTrusted, aTrusted, "Event is trusted");
+ checkTouches(aFakeEvent[aTouches], aEvent[aTouches]);
+ }
+}
+
+function checkTouches(aTouches1, aTouches2) {
+ is(aTouches1.length, aTouches2.length, "Correct touches length");
+ for (var i = 0; i < aTouches1.length; i++) {
+ checkTouch(aTouches1[i], aTouches2[i]);
+ }
+}
+
+function checkTouch(aFakeTouch, aTouch) {
+ is(aFakeTouch.identifier, aTouch.identifier, "Touch has correct identifier");
+ is(aFakeTouch.target, aTouch.target, "Touch has correct target");
+ is(aFakeTouch.page.x, aTouch.pageX, "Touch has correct pageX");
+ is(aFakeTouch.page.y, aTouch.pageY, "Touch has correct pageY");
+ is(aFakeTouch.page.x + Math.round(window.mozInnerScreenX), aTouch.screenX, "Touch has correct screenX");
+ is(aFakeTouch.page.y + Math.round(window.mozInnerScreenY), aTouch.screenY, "Touch has correct screenY");
+ is(aFakeTouch.page.x, aTouch.clientX, "Touch has correct clientX");
+ is(aFakeTouch.page.y, aTouch.clientY, "Touch has correct clientY");
+ is(aFakeTouch.radius.x, aTouch.radiusX, "Touch has correct radiusX");
+ is(aFakeTouch.radius.y, aTouch.radiusY, "Touch has correct radiusY");
+ is(aFakeTouch.rotationAngle, aTouch.rotationAngle, "Touch has correct rotationAngle");
+ is(aFakeTouch.force, aTouch.force, "Touch has correct force");
+}
+
+function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
+ var ids = [], xs=[], ys=[], rxs = [], rys = [],
+ rotations = [], forces = [];
+
+ for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
+ for (var i = 0; i < aEvent[touchType].length; i++) {
+ if (!ids.includes(aEvent[touchType][i].identifier)) {
+ ids.push(aEvent[touchType][i].identifier);
+ xs.push(aEvent[touchType][i].page.x);
+ ys.push(aEvent[touchType][i].page.y);
+ rxs.push(aEvent[touchType][i].radius.x);
+ rys.push(aEvent[touchType][i].radius.y);
+ rotations.push(aEvent[touchType][i].rotationAngle);
+ forces.push(aEvent[touchType][i].force);
+ }
+ }
+ }
+ return windowUtils.sendTouchEvent(aType,
+ ids, xs, ys, rxs, rys,
+ rotations, forces,
+ aModifiers, 0);
+}
+
+function touchEvent(aOptions) {
+ if (!aOptions) {
+ aOptions = {};
+ }
+ this.ctrlKey = aOptions.ctrlKey || false;
+ this.altKey = aOptions.altKey || false;
+ this.shiftKey = aOptions.shiftKey || false;
+ this.metaKey = aOptions.metaKey || false;
+ this.touches = aOptions.touches || [];
+ this.targetTouches = aOptions.targetTouches || [];
+ this.changedTouches = aOptions.changedTouches || [];
+}
+
+function testtouch(aOptions) {
+ if (!aOptions)
+ aOptions = {};
+ this.identifier = aOptions.identifier || 0;
+ this.target = aOptions.target || 0;
+ this.page = aOptions.page || {x: 0, y: 0};
+ this.radius = aOptions.radius || {x: 0, y: 0};
+ this.rotationAngle = aOptions.rotationAngle || 0;
+ this.force = aOptions.force || 1;
+}
+
+function testPreventDefault(name) {
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ let target = document.getElementById("testTarget");
+ let bcr = target.getBoundingClientRect();
+
+ let touch1 = new testtouch({
+ page: {x: Math.round(bcr.left + bcr.width/2),
+ y: Math.round(bcr.top + bcr.height/2)},
+ target
+ });
+
+ let event = new touchEvent({
+ touches: [touch1],
+ targetTouches: [touch1],
+ changedTouches: [touch1]
+ });
+
+ // test touchstart event fires correctly
+ var checkTouchesEvent = checkEvent(event, "touches");
+ var checkTargetTouches = checkEvent(event, "targetTouches");
+
+ /* This is the heart of the test. Verify that the touch event
+ looks correct both in and outside of a setTimeout */
+ window.addEventListener("touchstart", function(firedEvent) {
+ checkTouchesEvent(firedEvent, true);
+ setTimeout(function() {
+ checkTouchesEvent(firedEvent, true);
+ checkTargetTouches(firedEvent, true);
+
+ event.touches = [];
+ event.targetTouches = [];
+ sendTouchEvent(cwu, "touchend", event, 0);
+
+ nextTest();
+ }, 0);
+ });
+ sendTouchEvent(cwu, "touchstart", event, 0);
+}
+
+function doTest() {
+ tests.push(testPreventDefault);
+
+ tests.push(function() {
+ SimpleTest.finish();
+ });
+
+ nextTest();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(doTest);
+
+</script>
+</pre>
+<div id="parent">
+ <span id="testTarget" style="margin-left: 200px; padding: 5px; border: 1px solid black;">testTarget</span>
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug812744.html b/dom/events/test/test_bug812744.html
new file mode 100644
index 0000000000..2cd677b930
--- /dev/null
+++ b/dom/events/test/test_bug812744.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=812744
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 812744</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=812744">Mozilla Bug 812744</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id="f"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 812744 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ var f = $("f");
+ var el = f.contentDocument.documentElement;
+ f.onload = function() {
+ el.setAttribute("onmouseleave", "(void 0)");
+ is(el.onmouseleave, null, "Should not have a function here");
+ SimpleTest.finish();
+ };
+ f.src = "http://www.example.com/"
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug822898.html b/dom/events/test/test_bug822898.html
new file mode 100644
index 0000000000..ac7e18378b
--- /dev/null
+++ b/dom/events/test/test_bug822898.html
@@ -0,0 +1,343 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=822898
+-->
+<head>
+ <title>Test for Bug 822898</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=822898">Mozilla Bug 822898</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="subFrame"></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+
+/** Test for Bug 822898 - Pointer* Events **/
+
+let tests = [], testTarget, parent, iframeBody, gOnPointerPropHandled;
+
+function nextTest() {
+ if (tests.length)
+ SimpleTest.executeSoon(tests.shift());
+}
+
+function random() {
+ return Math.floor(Math.random() * 100);
+}
+
+function createTestEventValue(name) {
+
+ let detail = random();
+ let screenX = random();
+ let screenY = random();
+ let clientX = random();
+ let clientY = random();
+ let ctrlKey = !!(random() % 2);
+ let altKey = !!(random() % 2);
+ let shiftKey = !!(random() % 2);
+ let metaKey = !!(random() % 2);
+ let button = random();
+ let pointerId = random();
+
+ return function() {
+ let event = new PointerEvent("pointerdown", {
+ bubbles: true, cancelable: true, view: window,
+ detail, screenX, screenY, clientX, clientY,
+ ctrlKey, altKey, shiftKey, metaKey,
+ button, relatedTarget: null, pointerId
+ });
+
+
+ function check(ev) {
+ is(ev.detail, detail, "Correct detail");
+ is(ev.screenX, screenX, "Correct screenX");
+ is(ev.screenY, screenY, "Correct screenY");
+ is(ev.clientX, clientX, "Correct clientX");
+ is(ev.clientY, clientY, "Correct clientY");
+ is(ev.ctrlKey, ctrlKey, "Correct ctrlKey");
+ is(ev.altKey, altKey, "Correct altKey");
+ is(ev.shiftKey, shiftKey, "Correct shiftKey");
+ is(ev.metaKey, metaKey, "Correct metaKey");
+ is(ev.button, button, "Correct buttonArg");
+ is(ev.pointerId, pointerId, "Correct pointerId");
+ }
+
+ for (let target of [document, window, testTarget, parent])
+ target.addEventListener(name, check);
+
+ testTarget.dispatchEvent(event);
+
+ for (let target of [document, window, testTarget, parent])
+ target.removeEventListener(name, check);
+
+
+ nextTest();
+ }
+}
+
+function getDefaultArgEvent(eventname) {
+ return new PointerEvent(eventname, {
+ bubbles: true, cancelable: true, view: window,
+ detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+ button: 0, relatedTarget: null, pointerId: 0
+ });
+}
+
+function testDefaultArg() {
+ let event = getDefaultArgEvent("pointerdown");
+
+ testTarget.addEventListener("pointerdown", function(ev) {
+ is(ev.pointerId, 0, "Correct default pointerId");
+ }, {once: true});
+ testTarget.dispatchEvent(event);
+
+ nextTest();
+}
+
+function testStopPropagation() {
+ let event = getDefaultArgEvent("pointerdown");
+
+ let unreachableListener = function () {
+ ok(false, "Event should have been stopped");
+ }
+
+ // Capturing phase
+ let captured = false;
+ parent.addEventListener("pointerdown", function() {
+ captured = true;
+ }, {capture: true, once: true}); // Capturing phase
+
+ // Bubbling phase
+ parent.addEventListener("pointerdown", unreachableListener);
+
+ testTarget.addEventListener("pointerdown", function(ev) {
+ is(captured, true, "Event should have been captured");
+ ev.stopPropagation();
+ }, {once: true});
+
+ testTarget.dispatchEvent(event);
+
+ parent.removeEventListener("pointerdown", unreachableListener);
+
+ nextTest();
+}
+
+function testPreventDefault() {
+ let event = getDefaultArgEvent("pointerdown");
+
+ parent.addEventListener("pointerdown", function(ev) {
+ is(ev.defaultPrevented, true, "preventDefault can be called");
+ nextTest();
+ }, {once: true});
+
+ testTarget.addEventListener("pointerdown", function(ev) {
+ ev.preventDefault();
+ }, {once: true});
+
+ testTarget.dispatchEvent(event);
+}
+
+function testBlockPreventDefault() {
+ let event = new PointerEvent("pointerdown", {
+ bubbles: true, cancelable: false, view: window,
+ detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+ button: 0, relatedTarget: null, pointerId: 0, pointerType: "pen"
+ });
+
+ parent.addEventListener("pointerdown", function(ev) {
+ is(ev.defaultPrevented, false, "aCancelableArg works");
+ nextTest();
+ }, {once: true});
+
+ testTarget.addEventListener("pointerdown", function(ev) {
+ ev.preventDefault();
+ }, {once: true});
+
+ testTarget.dispatchEvent(event);
+}
+
+function testBlockBubbling() {
+ let unreachableListener = function () {
+ ok(false, "aCanBubble doesn't work");
+ }
+
+ let event = new PointerEvent("pointerdown", {
+ bubbles: false, cancelable: true, view: window,
+ detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+ button: 0, relatedTarget: null, pointerId: 0
+ });
+
+ parent.addEventListener("pointerdown", unreachableListener);
+ testTarget.dispatchEvent(event);
+ parent.removeEventListener("pointerdown", unreachableListener);
+
+ nextTest();
+}
+
+function testOnPointerProperty()
+{
+ iframeBody.onpointerdown = function (e) { gOnPointerPropHandled.pointerdown = true; }
+ iframeBody.onpointerup = function (e) { gOnPointerPropHandled.pointerup = true; }
+ iframeBody.onpointermove = function (e) { gOnPointerPropHandled.pointermove = true; }
+ iframeBody.onpointerout = function (e) { gOnPointerPropHandled.pointerout = true; }
+ iframeBody.onpointerover = function (e) { gOnPointerPropHandled.pointerover = true; }
+ iframeBody.onpointerenter = function (e) { gOnPointerPropHandled.pointerenter = true; }
+ iframeBody.onpointerleave = function (e) { gOnPointerPropHandled.pointerleave = true; }
+ iframeBody.onpointercancel = function (e) { gOnPointerPropHandled.pointercancel = true; }
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointerdown"));
+ is(gOnPointerPropHandled.pointerdown, true, "pointerdown property is performed");
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointerup"));
+ is(gOnPointerPropHandled.pointerup, true, "pointerup property is performed");
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointermove"));
+ is(gOnPointerPropHandled.pointermove, true, "pointermove property is performed");
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointerout"));
+ is(gOnPointerPropHandled.pointerout, true, "pointerout property is performed");
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointerover"));
+ is(gOnPointerPropHandled.pointerover, true, "pointerover property is performed");
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointerenter"));
+ is(gOnPointerPropHandled.pointerenter, true, "pointerenter property is performed");
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointerleave"));
+ is(gOnPointerPropHandled.pointerleave, true, "pointerleave property is performed");
+
+ iframeBody.dispatchEvent(getDefaultArgEvent("pointercancel"));
+ is(gOnPointerPropHandled.pointercancel, true, "pointercancel property is performed");
+
+ nextTest();
+}
+
+function testPointerEventCTORS()
+{
+ // TODO: This should go to test_eventctors.html, when PointerEvents enabled by default
+ var receivedEvent;
+ iframeBody.addEventListener("hello", function(e) { receivedEvent = e; }, true);
+
+ var e;
+ var ex = false;
+
+ try {
+ e = new PointerEvent();
+ } catch(exp) {
+ ex = true;
+ }
+ ok(ex, "PointerEvent: First parameter is required!");
+ ex = false;
+
+ e = new PointerEvent("hello");
+ is(e.type, "hello", "PointerEvent: Wrong event type!");
+ ok(!e.isTrusted, "PointerEvent: Event shouldn't be trusted!");
+ ok(!e.bubbles, "PointerEvent: Event shouldn't bubble!");
+ ok(!e.cancelable, "PointerEvent: Event shouldn't be cancelable!");
+ iframeBody.dispatchEvent(e);
+ is(receivedEvent, e, "PointerEvent: Wrong event!");
+
+ var PointerEventProps =
+ [ { screenX: 0 },
+ { screenY: 0 },
+ { clientX: 0 },
+ { clientY: 0 },
+ { ctrlKey: false },
+ { shiftKey: false },
+ { altKey: false },
+ { metaKey: false },
+ { button: 0 },
+ { buttons: 0 },
+ { relatedTarget: null },
+ { pointerId: 0 },
+ { pointerType: "" }
+ ];
+
+ var testPointerProps =
+ [
+ { screenX: 1 },
+ { screenY: 2 },
+ { clientX: 3 },
+ { clientY: 4 },
+ { ctrlKey: true },
+ { shiftKey: true },
+ { altKey: true },
+ { metaKey: true },
+ { button: 5 },
+ { buttons: 6 },
+ { relatedTarget: window },
+ { pointerId: 5 },
+ { pointerType: "mouse" }
+ ];
+
+ var defaultPointerEventValues = {};
+ for (var i = 0; i < PointerEventProps.length; ++i) {
+ for (prop in PointerEventProps[i]) {
+ ok(prop in e, "PointerEvent: PointerEvent doesn't have property " + prop + "!");
+ defaultPointerEventValues[prop] = PointerEventProps[i][prop];
+ }
+ }
+
+ while (testPointerProps.length) {
+ var p = testPointerProps.shift();
+ e = new PointerEvent("foo", p);
+ for (var def in defaultPointerEventValues) {
+ if (!(def in p)) {
+ is(e[def], defaultPointerEventValues[def],
+ "PointerEvent: Wrong default value for " + def + "!");
+ } else {
+ is(e[def], p[def], "PointerEvent: Wrong event init value for " + def + "!");
+ }
+ }
+ }
+ nextTest();
+}
+
+function runTests() {
+ testTarget = document.getElementById("testTarget");
+ parent = testTarget.parentNode;
+ gOnPointerPropHandled = new Array;
+ iframeBody = document.getElementById("subFrame").contentWindow.document.body;
+
+ tests.push(createTestEventValue("pointerdown"));
+ tests.push(createTestEventValue("pointermove"));
+ tests.push(createTestEventValue("pointerup"));
+
+ tests.push(testDefaultArg);
+ tests.push(testStopPropagation);
+
+ tests.push(testPreventDefault);
+ tests.push(testBlockPreventDefault);
+
+ tests.push(testBlockBubbling);
+ tests.push(testOnPointerProperty());
+ tests.push(testPointerEventCTORS());
+
+ tests.push(function() {
+ SimpleTest.finish();
+ });
+
+ nextTest();
+}
+
+window.onload = function() {
+ SpecialPowers.pushPrefEnv({"set":[["dom.w3c_pointer_events.enabled", true]]}, runTests);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div id="parent">
+ <span id="testTarget" style="border: 1px solid black;">testTarget</span>
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug855741.html b/dom/events/test/test_bug855741.html
new file mode 100644
index 0000000000..227d4d0b6d
--- /dev/null
+++ b/dom/events/test/test_bug855741.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=855741
+-->
+<head>
+ <title>Test for Bug 855741</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<input type="text" id="testTarget" value="focus">
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 855741 **/
+function testFocusEvent(event) {
+ ok(('relatedTarget' in event), 'FocusEvent.relatedTarget exists');
+
+ if (event.construct_test == true) {
+ ok(event.relatedTarget == $("content"), 'FocusEvent.relatedTarget is ' + $("content").id);
+ }
+}
+
+function testUIEvent(event) {
+ ok((event.detail == 0),
+ 'UIEvent.detail should be 0 in ' + event.target.value + ' event');
+
+ ok((event.defaultView == null),
+ 'UIEvent.defaultView should be null in ' + event.target.value + ' event');
+}
+
+function testEventType(event, type) {
+ ok((event.type == type), 'Event.type match: ' + type);
+}
+
+function eventhandle(event) {
+ testFocusEvent(event);
+ testUIEvent(event);
+ testEventType(event, event.target.value);
+
+ if (event.target.value == 'blur') {
+ event.target.value = 'focus';
+ } else {
+ event.target.value = 'blur';
+ }
+}
+
+//
+// event handler:
+//
+$("testTarget").addEventListener("focus", eventhandle, true);
+$("testTarget").addEventListener("blur", eventhandle, true);
+
+//
+// FocusEvent structure test
+//
+$("testTarget").focus();
+$("testTarget").blur();
+
+//
+// Focus/Blur constructor test
+//
+var focus_event = new FocusEvent("focus",
+ {bubbles: true,
+ cancelable: true,
+ relatedTarget: $("content")});
+focus_event.construct_test = true;
+
+var blur_event = new FocusEvent("blur",
+ {bubbles: true,
+ cancelable: true,
+ relatedTarget: $("content")});
+blur_event.construct_test = true;
+
+// create cycle referece for leak test
+$("content").foo_focus = focus_event;
+$("content").foo_blur = blur_event;
+
+$("testTarget").dispatchEvent(focus_event);
+$("testTarget").dispatchEvent(blur_event);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug864040.html b/dom/events/test/test_bug864040.html
new file mode 100644
index 0000000000..41f6b3dd25
--- /dev/null
+++ b/dom/events/test/test_bug864040.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=864040
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 864040</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=864040">Mozilla Bug 864040</a>
+<div id="display">
+ <textarea id="ta" rows="5" cols="20" style="-moz-appearance:none"></textarea>
+ <div id="ce" contentEditable="true" style="height: 5em;"></div>
+</div>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+ <script type="application/javascript">
+ /**
+ * Test for Bug 864040
+ *
+ * We use a selection event to set the selection to the end of an editor
+ * containing an ending newline. Then we test to see that the caret is
+ * actually drawn on the newline.
+ */
+
+ async function testSelectEndOfText(elem) {
+ var tn = elem.tagName;
+ elem.focus();
+
+ // Enter test string into editor
+ var test_string = 'test\n';
+ sendString(test_string);
+
+ // Get the caret position after what we entered
+ var result = synthesizeQuerySelectedText();
+ ok(result, tn + ': failed to query selection (1)');
+ var refoffset = result.offset;
+
+ // Take a snapshot of where the caret is (on the new line)
+ referenceSnapshot = await snapshotWindow(window, true /* withCaret */);
+ ok(referenceSnapshot, tn + ': failed to take snapshot (1)');
+
+ // Set selection to the same spot through a selection event
+ ok(synthesizeSelectionSet(refoffset, 0, false), tn + ': failed to set selection');
+
+ // Make sure new selection is the same
+ result = synthesizeQuerySelectedText();
+ ok(result, tn + ': failed to query selection (2)');
+ is(result.offset, refoffset, tn + ': caret is not at the right position');
+
+ // Take a snapshot of where the new caret is (shoud still be on the new line)
+ testSnapshot = await snapshotWindow(window, true /* withCaret */);
+ ok(testSnapshot, tn + ': failed to take snapshot (2)');
+
+ // Compare snapshot (should be the same)
+ result = compareSnapshots(referenceSnapshot, testSnapshot, true /* expected */)
+ ok(result, tn + ': failed to compare snapshots');
+ // result = [correct, s1data, s2data]
+ ok(result[0], tn + ': caret is not on new line');
+ if (!result[0]) {
+ dump('Ref: ' + result[1] + '\n');
+ dump('Res: ' + result[2] + '\n');
+ }
+ }
+
+ async function runTests() {
+ // we don't test regular <input> because this test is about multiline support
+ // test textarea
+ await testSelectEndOfText(document.getElementById('ta'));
+ // test contentEditable
+ await testSelectEndOfText(document.getElementById('ce'));
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+
+ SimpleTest.waitForFocus(runTests);
+ </script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug924087.html b/dom/events/test/test_bug924087.html
new file mode 100644
index 0000000000..58eecc99c4
--- /dev/null
+++ b/dom/events/test/test_bug924087.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=924087
+-->
+<head>
+ <title>Test for Bug 924087</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div contenteditable><a id="editable" href="#">editable link</a></div>
+<a id="noneditable" href="#">non-editable link</a>
+<input>
+<textarea></textarea>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 924087 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+ var editable = document.querySelector("#editable");
+ var noneditable = document.querySelector("#noneditable");
+ var input = document.querySelector("input");
+ var textarea = document.querySelector("textarea");
+ synthesizeMouseAtCenter(noneditable, {type:"mousedown"});
+ is(document.querySelector(":active:link"), noneditable, "Normal links should become :active");
+ synthesizeMouseAtCenter(noneditable, {type:"mouseup"});
+ synthesizeMouseAtCenter(editable, {type:"mousedown"});
+ is(document.querySelector(":active:link"), null, "Editable links should not become :active");
+ synthesizeMouseAtCenter(editable, {type:"mouseup"});
+ [input, textarea].forEach(textbox => {
+ synthesizeMouseAtCenter(textbox, {type:"mousedown"});
+ is(document.querySelector(textbox.localName + ":active"), textbox, "The textbox should become :active");
+ synthesizeMouseAtCenter(textbox, {type:"mouseup"});
+ });
+ SimpleTest.finish();
+});
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/events/test/test_bug930374-chrome.html b/dom/events/test/test_bug930374-chrome.html
new file mode 100644
index 0000000000..576844c23f
--- /dev/null
+++ b/dom/events/test/test_bug930374-chrome.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=930374
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 930374</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=930374">Mozilla Bug 930374</a>
+<div id="display">
+ <input id="input-text">
+</div>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ var gKeyPress = null;
+ function onKeyPress(aEvent)
+ {
+ gKeyPress = aEvent;
+ is(aEvent.target, document.getElementById("input-text"), "input element should have focus");
+ ok(!aEvent.defaultPrevented, "keypress event should be consumed before keypress event handler");
+ }
+
+ function runTests()
+ {
+ document.addEventListener("keypress", onKeyPress);
+ var input = document.getElementById("input-text");
+ input.focus();
+
+ input.addEventListener("input", function (aEvent) {
+ ok(gKeyPress,
+ "Test1: keypress event must be fired before an input event");
+ ok(gKeyPress.defaultPrevented,
+ "Test1: keypress event's defaultPrevented should be true in chrome even if it's consumed by default action handler of editor");
+ setTimeout(function () {
+ ok(gKeyPress.defaultPrevented,
+ "Test2: keypress event's defaultPrevented should be true after event dispatching finished");
+ SimpleTest.finish();
+ }, 0);
+ }, {once: true});
+
+ sendChar("a");
+ }
+
+ SimpleTest.waitForFocus(runTests);
+ </script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug930374-content.html b/dom/events/test/test_bug930374-content.html
new file mode 100644
index 0000000000..bcf2eadfb7
--- /dev/null
+++ b/dom/events/test/test_bug930374-content.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=930374
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 930374</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=930374">Mozilla Bug 930374</a>
+<div id="display">
+ <input id="input-text">
+</div>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ var gKeyPress = null;
+ function onKeyPress(aEvent)
+ {
+ gKeyPress = aEvent;
+ is(aEvent.target, document.getElementById("input-text"), "input element should have focus");
+ ok(!aEvent.defaultPrevented, "keypress event should be consumed before keypress event handler");
+ }
+
+ function runTests()
+ {
+ document.addEventListener("keypress", onKeyPress);
+ var input = document.getElementById("input-text");
+ input.focus();
+
+ input.addEventListener("input", function (aEvent) {
+ ok(gKeyPress,
+ "Test1: keypress event must be fired before an input event");
+ ok(!gKeyPress.defaultPrevented,
+ "Test1: keypress event's defaultPrevented should be false even though it's consumed by the default action handler of editor");
+ gKeyPress.preventDefault();
+ ok(gKeyPress.defaultPrevented,
+ "Test1: keypress event's defaultPrevented should become true because of a call of preventDefault()");
+ }, {once: true});
+
+ sendChar("a");
+ gKeyPress = null;
+
+ input.addEventListener("input", function (aEvent) {
+ ok(gKeyPress,
+ "Test2: keypress event must be fired before an input event");
+ ok(!gKeyPress.defaultPrevented,
+ "Test2: keypress event's defaultPrevented should be false even though it's consumed by the default action handler of editor");
+ setTimeout(function () {
+ ok(!gKeyPress.defaultPrevented,
+ "Test2: keypress event's defaultPrevented should not become true after event dispatching finished");
+ SimpleTest.finish();
+ }, 0);
+ }, {once: true});
+
+ sendChar("b");
+ }
+
+ SimpleTest.waitForFocus(runTests);
+ </script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug944011.html b/dom/events/test/test_bug944011.html
new file mode 100644
index 0000000000..a8a0720989
--- /dev/null
+++ b/dom/events/test/test_bug944011.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=944011
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 944011</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 944011 comment 24 - Event handlers should fire even if the
+ target comes from a non-current inner. **/
+ SimpleTest.waitForExplicitFinish();
+ var gLoadCount = 0;
+ function loaded() {
+ ++gLoadCount;
+ switch(gLoadCount) {
+ case 1:
+ ok(true, "Got first load");
+ oldBody = window[0].document.body;
+ oldBody.onclick = function() {
+ ok(true, "Got onclick");
+ SimpleTest.finish();
+ }
+ $('ifr').setAttribute('srcdoc', '<html><body>Second frame</body></html>');
+ break;
+ case 2:
+ ok(true, "Got second load");
+ oldBody.dispatchEvent(new MouseEvent('click'));
+ break;
+ default:
+ ok(false, "Unexpected load");
+ SimpleTest.finish();
+ }
+ }
+
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=944011">Mozilla Bug 944011</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="ifr" onload="loaded();" srcdoc="<html><body>foo</body></html>"></iframe>
+ <div name="testTarget"></div>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug944847.html b/dom/events/test/test_bug944847.html
new file mode 100644
index 0000000000..199c561d26
--- /dev/null
+++ b/dom/events/test/test_bug944847.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=944847
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 944847</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 944847 **/
+
+ var e1 = document.createElement("div");
+ is(e1.onclick, null);
+ e1.setAttribute("onclick", "");
+ isnot(e1.onclick, null);
+
+ var e2 = document.implementation.createHTMLDocument(null, null).createElement("div");
+ is(e2.onclick, null);
+ e2.setAttribute("onclick", "");
+ is(e2.onclick, null);
+
+ var e3 = document.createElement("div");
+ is(e3.onclick, null);
+ e3.setAttribute("onclick", "");
+ e2.ownerDocument.adoptNode(e3);
+ is(e3.onclick, null);
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=944847">Mozilla Bug 944847</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug946632.html b/dom/events/test/test_bug946632.html
new file mode 100644
index 0000000000..bd132c6356
--- /dev/null
+++ b/dom/events/test/test_bug946632.html
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=946632
+-->
+<head>
+ <title>Test for bug 946632 - propagate mouse-wheel vertical scroll events to container</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <script type="application/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ .scrollable {
+ overflow: scroll;
+ height: 200px;
+ width: 200px;
+ }
+ input {
+ font-size: 72px;
+ height: 20px;
+ width: 20px;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=946632">Mozilla Bug 946632</a>
+<p id="display"></p>
+<div id="container" class="scrollable">
+ <input value="value">
+ x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>x<br>
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+ SpecialPowers.pushPrefEnv({
+ "set":[["general.smoothScroll", false],
+ ["mousewheel.system_scroll_override_on_root_content.enabled", false]]
+ }, runTests)
+ }, window);
+
+var input = document.querySelector("input");
+var container = document.querySelector("#container");
+
+function reset()
+{
+ container.scrollTop = 0;
+ container.scrollLeft = 0;
+ input.scrollTop = 0;
+ input.scrollLeft = 0;
+ container.style.display='none';
+ container.getBoundingClientRect();
+}
+
+function prepare(check)
+{
+ container.style.display='';
+ container.getBoundingClientRect();
+ scrollHandler = function(event) {
+ window.removeEventListener("scroll", arguments.callee, true);
+ event.stopPropagation();
+ check(event)
+ setTimeout(nextTest,0);
+ };
+ window.addEventListener("scroll", scrollHandler, true);
+}
+
+var tests = [
+ {
+ check(event) {
+ is(event.target, container, "<input> vertical line scroll targets container");
+ ok(container.scrollTop > 0, "<input> vertical line scroll container.scrollTop");
+ is(container.scrollLeft, 0, "<input> vertical line scroll container.scrollLeft");
+ is(input.scrollTop, 0, "<input> horizontal line scroll input.scrollTop");
+ is(input.scrollLeft, 0, "<input> horizontal line scroll input.scrollLeft");
+ },
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0,
+ lineOrPageDeltaY: 1,
+ }
+ },
+ {
+ check(event) {
+ is(event.target, input, "<input> horizontal line scroll targets <input>");
+ is(input.scrollTop, 0, "<input> horizontal line scroll input.scrollTop");
+ ok(input.scrollLeft > 0, "<input> horizontal line scroll input.scrollLeft");
+ is(container.scrollTop, 0, "<input> horizontal line scroll container.scrollTop");
+ is(container.scrollLeft, 0, "<input> horizontal line scroll container.scrollLeft");
+ },
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0,
+ lineOrPageDeltaX: 1
+ }
+ },
+ {
+ check(event) {
+ is(event.target, container, "<input> vertical page scroll targets container");
+ ok(container.scrollTop > 0, "<input> vertical line scroll container.scrollTop");
+ is(container.scrollLeft, 0, "<input> vertical line scroll container.scrollLeft");
+ is(input.scrollTop, 0, "<input> vertical page scroll input.scrollTop");
+ is(input.scrollLeft, 0, "<input> vertical page scroll input.scrollLeft");
+ },
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0,
+ lineOrPageDeltaY: 1
+ }
+ },
+ {
+ check(event) {
+ is(event.target, input, "<input> horizontal page scroll targets <input>");
+ is(input.scrollTop, 0, "<input> horizontal page scroll input.scrollTop");
+ ok(input.scrollLeft > 0, "<input> horizontal page scroll input.scrollLeft");
+ is(container.scrollTop, 0, "<input> horizontal page scroll container.scrollTop");
+ is(container.scrollLeft, 0, "<input> horizontal page scroll container.scrollLeft");
+ },
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0,
+ lineOrPageDeltaX: 1
+ }
+ },
+];
+
+var i = 0;
+function nextTest()
+{
+ if (i == tests.length) {
+ SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
+ SimpleTest.finish();
+ return;
+ }
+ var test = tests[i];
+ ++i;
+ reset();
+
+ waitForApzFlushedRepaints(function() {
+ prepare(test.check);
+
+ sendWheelAndPaint(input, 8, 6, test.event, function() {
+ // Do nothing - we wait for the scroll event.
+ });
+ });
+}
+
+function runTests()
+{
+ nextTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug967796.html b/dom/events/test/test_bug967796.html
new file mode 100644
index 0000000000..6d22804e0b
--- /dev/null
+++ b/dom/events/test/test_bug967796.html
@@ -0,0 +1,243 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=967796
+-->
+<head>
+ <title>Test for Bug 967796</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=967796">Mozilla Bug 967796</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 967796 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(() => {
+ // Enable Pointer Events
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.w3c_pointer_events.enabled", true]
+ ]
+ }, runTests);
+});
+var outer;
+var middle;
+var inner;
+var outside;
+var container;
+var file;
+var iframe;
+var checkRelatedTarget = false;
+var expectedRelatedEnter = null;
+var expectedRelatedLeave = null;
+var pointerentercount = 0;
+var pointerleavecount = 0;
+var pointerovercount = 0;
+var pointeroutcount = 0;
+
+function sendMouseEventToElement(t, elem) {
+ var r = elem.getBoundingClientRect();
+ synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
+}
+
+var expectedPointerEnterTargets = [];
+var expectedPointerLeaveTargets = [];
+
+function runTests() {
+ outer = document.getElementById("outertest");
+ middle = document.getElementById("middletest");
+ inner = document.getElementById("innertest");
+ outside = document.getElementById("outside");
+ container = document.getElementById("container");
+ file = document.getElementById("file");
+ iframe = document.getElementById("iframe");
+ iframe.addEventListener("pointerenter", penter);
+ iframe.addEventListener("pointerleave", pleave);
+ iframe.addEventListener("pointerout", pout);
+ iframe.addEventListener("pointerover", pover);
+
+ // Make sure ESM thinks pointer is outside the test elements.
+ sendMouseEventToElement("mousemove", outside);
+
+ pointerentercount = 0;
+ pointerleavecount = 0;
+ pointerovercount = 0;
+ pointeroutcount = 0;
+ checkRelatedTarget = true;
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = inner;
+ expectedPointerEnterTargets = ["outertest", "middletest", "innertest"];
+ sendMouseEventToElement("mousemove", inner);
+ is(pointerentercount, 3, "Unexpected pointerenter event count!");
+ is(pointerovercount, 1, "Unexpected pointerover event count!");
+ is(pointeroutcount, 0, "Unexpected pointerout event count!");
+ is(pointerleavecount, 0, "Unexpected pointerleave event count!");
+ expectedRelatedEnter = inner;
+ expectedRelatedLeave = outside;
+ expectedPointerLeaveTargets = ["innertest", "middletest", "outertest"];
+ sendMouseEventToElement("mousemove", outside);
+ is(pointerentercount, 3, "Unexpected pointerenter event count!");
+ is(pointerovercount, 1, "Unexpected pointerover event count!");
+ is(pointeroutcount, 1, "Unexpected pointerout event count!");
+ is(pointerleavecount, 3, "Unexpected pointerleave event count!");
+
+ // Event handling over native anonymous content.
+ var r = file.getBoundingClientRect();
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = file;
+ synthesizeMouse(file, r.width / 6, r.height / 2, {type: "mousemove"});
+ is(pointerentercount, 4, "Unexpected pointerenter event count!");
+ is(pointerovercount, 2, "Unexpected pointerover event count!");
+ is(pointeroutcount, 1, "Unexpected pointerout event count!");
+ is(pointerleavecount, 3, "Unexpected pointerleave event count!");
+
+ // Moving pointer over type="file" shouldn't cause pointerover/out/enter/leave events
+ synthesizeMouse(file, r.width - (r.width / 6), r.height / 2, {type: "mousemove"});
+ is(pointerentercount, 4, "Unexpected pointerenter event count!");
+ is(pointerovercount, 2, "Unexpected pointerover event count!");
+ is(pointeroutcount, 1, "Unexpected pointerout event count!");
+ is(pointerleavecount, 3, "Unexpected pointerleave event count!");
+
+ expectedRelatedEnter = file;
+ expectedRelatedLeave = outside;
+ sendMouseEventToElement("mousemove", outside);
+ is(pointerentercount, 4, "Unexpected pointerenter event count!");
+ is(pointerovercount, 2, "Unexpected pointerover event count!");
+ is(pointeroutcount, 2, "Unexpected pointerout event count!");
+ is(pointerleavecount, 4, "Unexpected pointerleave event count!");
+
+ // Initialize iframe
+ iframe.contentDocument.documentElement.style.overflow = "hidden";
+ iframe.contentDocument.body.style.margin = "0px";
+ iframe.contentDocument.body.style.width = "100%";
+ iframe.contentDocument.body.style.height = "100%";
+ iframe.contentDocument.body.innerHTML =
+ "<div style='width: 100%; height: 50%; border: 1px solid black;'></div>" +
+ "<div style='width: 100%; height: 50%; border: 1px solid black;'></div>";
+ iframe.contentDocument.body.offsetLeft; // flush
+
+ iframe.contentDocument.body.firstChild.onpointerenter = penter;
+ iframe.contentDocument.body.firstChild.onpointerleave = pleave;
+ iframe.contentDocument.body.lastChild.onpointerenter = penter;
+ iframe.contentDocument.body.lastChild.onpointerleave = pleave;
+ r = iframe.getBoundingClientRect();
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = iframe;
+ // Move pointer inside the iframe.
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height / 4, {type: "mousemove"},
+ iframe.contentWindow);
+ is(pointerentercount, 6, "Unexpected pointerenter event count!");
+ is(pointerleavecount, 4, "Unexpected pointerleave event count!");
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height - (r.height / 4), {type: "mousemove"},
+ iframe.contentWindow);
+ is(pointerentercount, 7, "Unexpected pointerenter event count!");
+ is(pointerleavecount, 5, "Unexpected pointerleave event count!");
+ expectedRelatedEnter = iframe;
+ expectedRelatedLeave = outside;
+ sendMouseEventToElement("mousemove", outside);
+ is(pointerentercount, 7, "Unexpected pointerenter event count!");
+ is(pointerleavecount, 7, "Unexpected pointerleave event count!");
+
+ // pointerdown must produce pointerenter event
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = iframe;
+ // Move pointer inside the iframe.
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height / 4, {type: "mousedown"},
+ iframe.contentWindow);
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height - (r.height / 4), {type: "mousedown"},
+ iframe.contentWindow);
+ is(pointerentercount, 10, "Unexpected pointerenter event count!");
+
+ // pointerdown + pointermove must produce single pointerenter event
+ expectedRelatedEnter = outside;
+ expectedRelatedLeave = iframe;
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2, r.height / 4, {type: "mousedown"},
+ iframe.contentWindow);
+ synthesizeMouse(iframe.contentDocument.body, r.width / 2 + 1, r.height / 4 + 1, {type: "mousemove"},
+ iframe.contentWindow);
+ is(pointerentercount, 11, "Unexpected pointerenter event count!");
+
+ Array.from(document.querySelectorAll('*'))
+ .concat([iframe.contentDocument.body.firstChild, iframe.contentDocument.body.lastChild])
+ .forEach((elt) => {
+ elt.onpointerenter = null;
+ elt.onpointerleave = null;
+ elt.onpointerenter = null;
+ elt.onpointerleave = null;
+ });
+ SimpleTest.finish();
+}
+
+function penter(evt) {
+ ++pointerentercount;
+ evt.stopPropagation();
+ if (expectedPointerEnterTargets.length) {
+ var t = expectedPointerEnterTargets.shift();
+ is(evt.target.id, t, "Wrong event target!");
+ }
+ is(evt.bubbles, false, evt.type + " should not bubble!");
+ is(evt.cancelable, false, evt.type + " is cancelable!");
+ is(evt.target, evt.currentTarget, "Wrong event target!");
+ ok(!evt.relatedTarget || evt.target.ownerDocument == evt.relatedTarget.ownerDocument,
+ "Leaking nodes to another document?");
+ if (checkRelatedTarget && evt.target.ownerDocument == document) {
+ is(evt.relatedTarget, expectedRelatedEnter, "Wrong related target (pointerenter)");
+ }
+}
+
+function pleave(evt) {
+ ++pointerleavecount;
+ evt.stopPropagation();
+ if (expectedPointerLeaveTargets.length) {
+ var t = expectedPointerLeaveTargets.shift();
+ is(evt.target.id, t, "Wrong event target!");
+ }
+ is(evt.bubbles, false, evt.type + " should not bubble!");
+ is(evt.cancelable, false, evt.type + " is cancelable!");
+ is(evt.target, evt.currentTarget, "Wrong event target!");
+ ok(!evt.relatedTarget || evt.target.ownerDocument == evt.relatedTarget.ownerDocument,
+ "Leaking nodes to another document?");
+ if (checkRelatedTarget && evt.target.ownerDocument == document) {
+ is(evt.relatedTarget, expectedRelatedLeave, "Wrong related target (pointerleave)");
+ }
+}
+
+function pover(evt) {
+ ++pointerovercount;
+ evt.stopPropagation();
+}
+
+function pout(evt) {
+ ++pointeroutcount;
+ evt.stopPropagation();
+}
+
+</script>
+</pre>
+<div id="container" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+ onpointerout="pout(event)" onpointerover="pover(event)">
+ <div id="outside" onpointerout="event.stopPropagation()" onpointerover="event.stopPropagation()">foo</div>
+ <div id="outertest" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+ onpointerout="pout(event)" onpointerover="pover(event)">
+ <div id="middletest" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+ onpointerout="pout(event)" onpointerover="pover(event)">
+ <div id="innertest" onpointerenter="penter(event)" onpointerleave="pleave(event)"
+ onpointerout="pout(event)" onpointerover="pover(event)">foo</div>
+ </div>
+ </div>
+ <input type="file" id="file"
+ onpointerenter="penter(event)" onpointerleave="pleave(event)"
+ onpointerout="pout(event)" onpointerover="pover(event)">
+ <br>
+ <iframe id="iframe" width="50" height="50"></iframe>
+</div>
+</body>
+</html>
diff --git a/dom/events/test/test_bug985988.html b/dom/events/test/test_bug985988.html
new file mode 100644
index 0000000000..51d02d828f
--- /dev/null
+++ b/dom/events/test/test_bug985988.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=985988
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 985988</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 985988 **/
+
+ function handler() {
+ return false;
+ }
+
+ function reversedHandler() {
+ return true;
+ }
+
+ function test() {
+ var t = document.getElementById("testtarget");
+
+ t.onclick = handler;
+ var e = new MouseEvent("click", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(e.defaultPrevented, "Should have prevented default handling.");
+
+ t.onclick = reversedHandler;
+ e = new MouseEvent("click", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(!e.defaultPrevented, "Shouldn't have prevented default handling.");
+
+ t.onmouseover = handler;
+ e = new MouseEvent("mouseover", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(e.defaultPrevented, "Should have prevented default handling.");
+
+ t.onmouseover = reversedHandler;
+ e = new MouseEvent("mouseover", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(!e.defaultPrevented, "Shouldn't have prevented default handling.");
+
+ // error does not have reversed meaning for handler return value on
+ // non-globals.
+ t.onerror = handler;
+ e = new ErrorEvent("error", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(e.defaultPrevented, "Should have prevented default handling.");
+
+ t.onerror = reversedHandler;
+ e = new ErrorEvent("error", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(!e.defaultPrevented, "Shouldn't have prevented default handling.");
+
+ // error has reversed meaning for handler return value on globals.
+ t = document.getElementById("testtarget2").contentWindow;
+ t.onerror = reversedHandler;
+ e = new ErrorEvent("error", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(e.defaultPrevented, "Should have prevented default handling.");
+
+ t.onerror = handler;
+ e = new ErrorEvent("error", {cancelable: true});
+ t.dispatchEvent(e);
+ ok(!e.defaultPrevented, "Shouldn't have prevented default handling.");
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(test);
+
+ </script>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=985988">Mozilla Bug 985988</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<a href="#" id="testtarget">test target</a>
+<iframe id="testtarget2"></iframe>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_bug998809.html b/dom/events/test/test_bug998809.html
new file mode 100644
index 0000000000..0fc50ec547
--- /dev/null
+++ b/dom/events/test/test_bug998809.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=998809
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 998809</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 998809 **/
+ var event1 = document.createEvent("Event");
+ event1.initEvent("a", false, false);
+ event1.initEvent("b", false, false);
+ is(event1.type, "b");
+ var event2 = document.createEvent("Event");
+ event2.initEvent("a", false, false);
+ is(event2.type, "a");
+ event2.initEvent("b", false, false);
+ is(event2.type, "b");
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=998809">Mozilla Bug 998809</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_click_on_reframed_generated_text.html b/dom/events/test/test_click_on_reframed_generated_text.html
new file mode 100644
index 0000000000..e8c8b092d6
--- /dev/null
+++ b/dom/events/test/test_click_on_reframed_generated_text.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>Test for bug 1497524: Unbound generated content in the active chain</title>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<style>
+#target::before {
+ content: "X";
+ color: green;
+}
+</style>
+Should get a click event when clicking on the X below.
+<div id="target"></div>
+<script>
+SimpleTest.waitForExplicitFinish();
+let target = document.getElementById("target");
+
+target.addEventListener("mousedown", () => target.style.display = "inline");
+target.addEventListener("mouseup", () => target.style.display = "block");
+target.addEventListener("click", () => {
+ ok(true, "Got click event");
+ SimpleTest.finish();
+});
+
+onload = function() {
+ requestAnimationFrame(() => {
+ synthesizeMouseAtCenter(target, { type: "mousedown" })
+ requestAnimationFrame(() => {
+ synthesizeMouseAtCenter(target, { type: "mouseup" })
+ });
+ });
+}
+</script>
diff --git a/dom/events/test/test_click_on_restyled_element.html b/dom/events/test/test_click_on_restyled_element.html
new file mode 100644
index 0000000000..a79789ce74
--- /dev/null
+++ b/dom/events/test/test_click_on_restyled_element.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for clicking on an element which is restyled/reframed by mousedown event</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ .before-pseudo-element *:active::before {
+ content: "";
+ display: block;
+ height: 2px;
+ position: absolute;
+ top: -2px;
+ left: 0;
+ width: 100%;
+ }
+ .position-relative *:active {
+ position: relative;
+ top: 1px;
+ }
+ </style>
+</head>
+<body>
+<section class="before-pseudo-element"><a href="about:blank">link</a></section><!-- bug 1398196 -->
+<section class="before-pseudo-element"><span>span</span></section>
+<section class="position-relative"><a href="about:blank">link</a></section><!-- bug 1506508 -->
+<section class="position-relative"><span>span</span></section>
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function doTest() {
+ for (let sectionId of ["before-pseudo-element", "position-relative"]) {
+ for (let element of ["a", "span"]) {
+ let target = document.querySelector(`section.${sectionId} ${element}`);
+ target.scrollIntoView(true);
+ let clicked = false;
+ target.addEventListener("click", (aEvent) => {
+ is(aEvent.target, target, `click event is fired on the <${element}> element in ${sectionId} section as expected`);
+ aEvent.preventDefault();
+ clicked = true;
+ }, {once: true});
+ synthesizeMouseAtCenter(target, {});
+ ok(clicked, `Click event should've been fired on the <${element}> element in ${sectionId} section`);
+ }
+ }
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_clickevent_on_input.html b/dom/events/test/test_clickevent_on_input.html
new file mode 100644
index 0000000000..6f180d447b
--- /dev/null
+++ b/dom/events/test/test_clickevent_on_input.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test click event on input</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display">
+<input id="input"
+ style="position: absolute; top: 5px; left: 5px; border: solid 15px blue; width: 100px; height: 20px;"
+ onclick="gClickCount++;">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+var gClickCount = 0;
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests);
+
+var input = document.getElementById("input");
+
+function runTests()
+{
+ for (var i = 0; i < 3; i++) {
+ doTest(i);
+ }
+
+ // Re-test left clicking when the input element has some text.
+ gClickCount = 0;
+ input.value = "Long text Long text Long text Long text Long text Long text";
+ doTest(0);
+
+ input.style.display = "none";
+ SimpleTest.finish();
+}
+
+function isEnabledMiddleClickPaste()
+{
+ try {
+ return SpecialPowers.getBoolPref("middlemouse.paste");
+ } catch (e) {
+ return false;
+ }
+}
+
+function isEnabledAccessibleCaret()
+{
+ try {
+ return SpecialPowers.getBoolPref("layout.accessiblecaret.enabled");
+ } catch (e) {
+ return false;
+ }
+}
+
+function doTest(aButton)
+{
+ // NOTE #1: Non-primary buttons don't generate 'click' events
+ // NOTE #2: If touch caret is enabled, touch caret would ovelap input element,
+ // then, the click event isn't generated.
+ if (aButton != 2 &&
+ aButton != 1 &&
+ (aButton != 0 || !isEnabledAccessibleCaret())) {
+ gClickCount = 0;
+ // click on border of input
+ synthesizeMouse(input, 5, 5, { button: aButton });
+ is(gClickCount, 1,
+ "click event doesn't fired on input element (button is " +
+ aButton + ")");
+
+ gClickCount = 0;
+ // down on border
+ synthesizeMouse(input, 5, 5, { type: "mousedown", button: aButton });
+ // up on anonymous div of input
+ synthesizeMouse(input, 20, 20, { type: "mouseup", button: aButton });
+ is(gClickCount, 1,
+ "click event doesn't fired on input element (button is " +
+ aButton + ")");
+
+ gClickCount = 0;
+ // down on anonymous div of input
+ synthesizeMouse(input, 20, 20, { type: "mousedown", button: aButton });
+ // up on border
+ synthesizeMouse(input, 5, 5, { type: "mouseup", button: aButton });
+ is(gClickCount, 1,
+ "click event doesn't fired on input element (button is " +
+ aButton + ")");
+ }
+
+ gClickCount = 0;
+ // down on outside of input
+ synthesizeMouse(input, -3, -3, { type: "mousedown", button: aButton });
+ // up on border
+ synthesizeMouse(input, 5, 5, { type: "mouseup", button: aButton });
+ is(gClickCount, 0,
+ "click event is fired on input element unexpectedly (button is " +
+ aButton + ")");
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_coalesce_touchmove.html b/dom/events/test/test_coalesce_touchmove.html
new file mode 100644
index 0000000000..b1f5ffe55a
--- /dev/null
+++ b/dom/events/test/test_coalesce_touchmove.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>touchmove coalescing</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ function start() {
+ window.open("file_coalesce_touchmove.html");
+ }
+ </script>
+</head>
+<body onload="start();">
+</body>
+</html>
diff --git a/dom/events/test/test_continuous_wheel_events.html b/dom/events/test/test_continuous_wheel_events.html
new file mode 100644
index 0000000000..25ee5f17a2
--- /dev/null
+++ b/dom/events/test/test_continuous_wheel_events.html
@@ -0,0 +1,3290 @@
+<!DOCTYPE HTML>
+<html style="font-size: 32px;">
+<head>
+ <title>Test for D3E WheelEvent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="bodyLoaded()">
+<p id="display"></p>
+<div id="scrollable" style="font-family:monospace; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
+ <div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ </div>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+var gScrollableElement;
+var gScrolledElement;
+
+SimpleTest.waitForExplicitFinish();
+function bodyLoaded() {
+ gScrollableElement = document.getElementById("scrollable");
+ gScrolledElement = document.getElementById("scrolled");
+ runTests();
+}
+
+var gLineHeight = 0;
+var gHorizontalLine = 0;
+var gPageHeight = 0;
+var gPageWidth = 0;
+
+function sendWheelAndWait(aX, aY, aEvent)
+{
+ sendWheelAndPaint(gScrollableElement, aX, aY, aEvent, continueTest);
+}
+
+function* prepareScrollUnits()
+{
+ var result = -1;
+ function handler(aEvent)
+ {
+ result = aEvent.detail;
+ aEvent.preventDefault();
+ }
+ window.addEventListener("MozMousePixelScroll", handler, { capture: true, passive: false });
+
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gLineHeight = result;
+ ok(gLineHeight > 10 && gLineHeight < 25, "prepareScrollUnits: gLineHeight may be illegal value, got " + gLineHeight);
+
+ result = -1;
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gHorizontalLine = result;
+ ok(gHorizontalLine > 5 && gHorizontalLine < 16, "prepareScrollUnits: gHorizontalLine may be illegal value, got " + gHorizontalLine);
+
+ result = -1;
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gPageHeight = result;
+ // XXX Cannot we know the actual scroll port size?
+ ok(gPageHeight >= 150 && gPageHeight <= 200,
+ "prepareScrollUnits: gPageHeight is strange value, got " + gPageHeight);
+
+ result = -1;
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gPageWidth = result;
+ ok(gPageWidth >= 150 && gPageWidth <= 200,
+ "prepareScrollUnits: gPageWidth is strange value, got " + gPageWidth);
+
+ window.removeEventListener("MozMousePixelScroll", handler, true);
+}
+
+// Tests continuous trusted wheel events. Trusted wheel events should cause
+// legacy mouse scroll events when its lineOrPageDelta value is not zero or
+// accumulated delta values of pixel scroll events of pixel only device
+// become over the line height.
+function* testContinuousTrustedEvents()
+{
+ const kSynthesizedWheelEventTests = [
+ { description: "Simple horizontal wheel event by pixels (16.0 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 16 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by pixels (16.0 - 1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 16 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by pixels (16.0 - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 16 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Simple vertical wheel event by pixels (16.0 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 16 } }
+ },
+ { description: "Simple vertical wheel event by pixels (16.0 - 1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 16 } }
+ },
+ { description: "Simple vertical wheel event by pixels (16.0 - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 16 } }
+ },
+
+ { description: "Simple z-direction wheel event by pixels (16.0 - 1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Simple horizontal wheel event by pixels (-16.0 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -16 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by pixels (-16.0 - -1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -16 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by pixels (-16.0 - -1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -16 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Simple vertical wheel event by pixels (-16.0 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -16 } }
+ },
+ { description: "Simple vertical wheel event by pixels (-16.0 - -1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -16 } }
+ },
+ { description: "Simple vertical wheel event by pixels (-16.0 - -1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -16 } }
+ },
+
+ { description: "Simple z-direction wheel event by pixels (-16.0 - -1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: -16.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: -16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ // 3 scroll events per line, and legacy line scroll will be fired first.
+ { description: "Horizontal wheel event by pixels (5.3 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Horizontal wheel event by pixels (5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Vertical wheel event by pixels (5.3 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "Vertical wheel event by pixels (5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "Vertical wheel event by pixels (5.3 - 0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+
+ { description: "Horizontal wheel event by pixels (-5.3 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Horizontal wheel event by pixels (-5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Horizontal wheel event by pixels (-5.3 - 0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Vertical wheel event by pixels (-5.3 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "Vertical wheel event by pixels (-5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "Vertical wheel event by pixels (-5.3 - 0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+
+ // 3 scroll events per line, and legacy line scroll will be fired last.
+ { description: "Horizontal wheel event by pixels (5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Horizontal wheel event by pixels (5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Horizontal wheel event by pixels (5.3 - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Vertical wheel event by pixels (5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "Vertical wheel event by pixels (5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "Vertical wheel event by pixels (5.3 - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+
+ { description: "Horizontal wheel event by pixels (-5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Horizontal wheel event by pixels (-5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Horizontal wheel event by pixels (-5.3 - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Vertical wheel event by pixels (-5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "Vertical wheel event by pixels (-5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "Vertical wheel event by pixels (-5.3 - -1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+
+ // Oblique scroll.
+ { description: "To bottom-right wheel event by pixels (5.3/5.2 - 1/1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "To bottom-right wheel event by pixels (5.3/5.2 - 0/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "To bottom-right wheel event by pixels (5.3/5.2 - 0/0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+
+ { description: "To bottom-left wheel event by pixels (-5.3/5.3 - -1/1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "To bottom-left wheel event by pixels (-5.3/5.3 - 0/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "To bottom-left wheel event by pixels (-5.3/5.3 - 0/0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+
+ { description: "To top-left wheel event by pixels (-5.2/-5.3 - -1/-1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "To top-left wheel event by pixels (-5.2/-5.3 - 0/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "To top-left wheel event by pixels (-5.2/-5.3 - 0/0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+
+ { description: "To top-right wheel event by pixels (5.3/-5.3 - 1/-1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "To top-right wheel event by pixels (5.3/-5.3 - 0/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+
+ // Pixel scroll only device's test. the lineOrPageDelta values should be computed
+ // by ESM. When changing the direction for each delta value, it should be
+ // reset at that time.
+ { description: "Pixel only device's horizontal wheel event by pixels (5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Pixel only device's horizontal wheel event by pixels (5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Pixel only device's horizontal wheel event by pixels (5.3 - 0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 0) #4",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 1.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 1) #5",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 5 } }
+ },
+
+ { description: "Pixel only device's horizontal wheel event by pixels (-5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Pixel only device's horizontal wheel event by pixels (-5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Pixel only device's horizontal wheel event by pixels (-5.3 - 0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - 0) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - 0) #4",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -1.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } }
+ },
+ { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - -1) #5",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -5 } }
+ },
+
+ // ESM should reset an accumulated delta value only when the direction of it
+ // is changed but shouldn't reset the other delta.
+ { description: "Pixel only device's bottom-right wheel event by pixels (5.3/4.9 - 0/0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: 4 } }
+ },
+ { description: "Pixel only device's bottom-right wheel event by pixels (5.3/4.9 - 0/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: 4 } }
+ },
+ { description: "Pixel only device's bottom-left wheel event by pixels (-5.3/4.9 - 0/0) #4",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: 4 } }
+ },
+ // the accumulated X should be 0 here, but Y shouldn't be reset.
+ { description: "Pixel only device's bottom-right wheel event by pixels (5.3/4.9 - 0/0) #5",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 5.3, deltaY: 1.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 5.3, deltaY: 1.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 5 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } }
+ },
+
+ { description: "Pixel only device's top-left wheel event by pixels (-5.3/-4.9 - 0/0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: -4 } }
+ },
+ { description: "Pixel only device's top-left wheel event by pixels (-5.3/-4.9 - 0/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: -4 } }
+ },
+ { description: "Pixel only device's bottom-left wheel event by pixels (-5.3/4.9 - 0/0) #4",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: 4 } }
+ },
+ // the accumulated Y should be 0 here, but X shouldn't be reset.
+ { description: "Pixel only device's top-left wheel event by pixels (-5.3/-4.9 - 0/0) #5",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: true,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -5 },
+ vertical: { expected: true, preventDefault: false, detail: -4 } }
+ },
+
+ // Simple line scroll tests.
+ { description: "Simple horizontal wheel event by lines (1.0 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gHorizontalLine },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by lines (1.0 - 1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gHorizontalLine },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Simple horizontal wheel event by lines (-1.0 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -gHorizontalLine },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by lines (-1.0 - -1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -gHorizontalLine },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Simple vertical wheel event by lines (-1.0 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -gLineHeight } }
+ },
+ { description: "Simple vertical wheel event by lines (-1.0 - -1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -gLineHeight } }
+ },
+
+ { description: "Simple vertical wheel event by lines (1.0 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: gLineHeight } }
+ },
+ { description: "Simple vertical wheel event by lines (1.0 - 1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: gLineHeight } }
+ },
+
+ // high resolution line scroll
+ { description: "High resolution horizontal wheel event by lines (0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by lines (0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by lines (0.333... - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "High resolution horizontal wheel event by lines (-0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -Math.floor(gHorizontalLine / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by lines (-0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -Math.floor(gHorizontalLine / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by lines (-0.333... - -1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -Math.floor(gHorizontalLine / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "High resolution vertical wheel event by lines (0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by lines (0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by lines (0.333... - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+ },
+
+ { description: "High resolution vertical wheel event by lines (-0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -Math.floor(gLineHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by lines (-0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -Math.floor(gLineHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by lines (-0.333... - -1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -Math.floor(gLineHeight / 3) } }
+ },
+
+ // Oblique line scroll
+ { description: "Oblique wheel event by lines (-1.0/2.0 - -1/2)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 2, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: true, preventDefault: false, detail: 2 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -gHorizontalLine },
+ vertical: { expected: true, preventDefault: false, detail: gLineHeight * 2 } }
+ },
+
+ { description: "Oblique wheel event by lines (1.0/-2.0 - 1/-2)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: -2, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: -2 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: false, detail: -gLineHeight * 2 } }
+ },
+
+ { description: "High resolution oblique wheel event by lines (0.5/0.333.../-0.8 - 0/0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine / 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+ },
+ { description: "High resolution oblique wheel event by lines (0.5/0.333.../-0.8 - 1/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine / 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+ },
+ { description: "High resolution oblique wheel event by lines (0.5/0.333.../-0.8 - 0/1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine / 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+ },
+
+ // Simple page scroll tests.
+ { description: "Simple horizontal wheel event by pages (1.0 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gPageWidth },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by pages (1.0 - 1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gPageWidth },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Simple horizontal wheel event by pages (-1.0 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -gPageWidth },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "Simple horizontal wheel event by pages (-1.0 - -1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -gPageWidth },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "Simple vertical wheel event by pages (-1.0 - -1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -gPageHeight } }
+ },
+ { description: "Simple vertical wheel event by pages (-1.0 - -1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -gPageHeight } }
+ },
+
+ { description: "Simple vertical wheel event by pages (1.0 - 1) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: gPageHeight } }
+ },
+ { description: "Simple vertical wheel event by pages (1.0 - 1) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: gPageHeight } }
+ },
+
+ // high resolution page scroll
+ { description: "High resolution horizontal wheel event by pages (0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by pages (0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by pages (0.333... - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "High resolution horizontal wheel event by pages (-0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -Math.floor(gPageWidth / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by pages (-0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -Math.floor(gPageWidth / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+ { description: "High resolution horizontal wheel event by pages (-0.333... - -1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -Math.floor(gPageWidth / 3) },
+ vertical: { expected: false, preventDefault: false, detail: 0 } }
+ },
+
+ { description: "High resolution vertical wheel event by pages (0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by pages (0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by pages (0.333... - 1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+ },
+
+ { description: "High resolution vertical wheel event by pages (-0.333... - 0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -Math.floor(gPageHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by pages (-0.333... - 0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -Math.floor(gPageHeight / 3) } }
+ },
+ { description: "High resolution vertical wheel event by pages (-0.333... - -1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -Math.floor(gPageHeight / 3) } }
+ },
+
+ // Oblique page scroll
+ { description: "Oblique wheel event by pages (-1.0/2.0 - -1/2)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 2, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -gPageWidth },
+ vertical: { expected: true, preventDefault: false, detail: gPageHeight * 2 } }
+ },
+
+ { description: "Oblique wheel event by pages (1.0/-2.0 - 1/-2)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: -2, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: false, detail: -gPageHeight * 2 } }
+ },
+
+ { description: "High resolution oblique wheel event by pages (0.5/0.333.../-0.8 - 0/0) #1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth / 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+ },
+ { description: "High resolution oblique wheel event by pages (0.5/0.333.../-0.8 - 1/0) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth / 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+ },
+ { description: "High resolution oblique wheel event by pages (0.5/0.333.../-0.8 - 0/1) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth / 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+ },
+
+ // preventDefault() shouldn't prevent other legacy events.
+ { description: "preventDefault() shouldn't prevent other legacy events (pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: 1 },
+ vertical: { expected: true, preventDefault: true, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: 16 },
+ vertical: { expected: true, preventDefault: true, detail: 16 } },
+ },
+ { description: "preventDefault() shouldn't prevent other legacy events (line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: 1 },
+ vertical: { expected: true, preventDefault: true, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: true, detail: gLineHeight } },
+ },
+ { description: "preventDefault() shouldn't prevent other legacy events (page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: true, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: true, detail: gPageHeight } },
+ },
+
+ // If wheel event is consumed by preventDefault(), legacy events are not necessary.
+ { description: "If wheel event is consumed by preventDefault(), legacy events are not necessary (pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: true,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ },
+ { description: "If wheel event is consumed by preventDefault(), legacy events are not necessary (line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: true,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ },
+ { description: "If wheel event is consumed by preventDefault(), legacy events are not necessary (page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: true,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ },
+
+ // modifier key state tests
+ { description: "modifier key tests (shift, pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: 16 },
+ vertical: { expected: true, preventDefault: true, detail: 16 } },
+ },
+ { description: "modifier key tests (shift, line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: true, detail: gLineHeight } },
+ },
+ { description: "modifier key tests (shift, page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: true, detail: gPageHeight } },
+ },
+
+ { description: "modifier key tests (ctrl, pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: 16 },
+ vertical: { expected: true, preventDefault: true, detail: 16 } },
+ },
+ { description: "modifier key tests (ctrl, line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: true, detail: gLineHeight } },
+ },
+ { description: "modifier key tests (ctrl, page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: true, detail: gPageHeight } },
+ },
+
+ { description: "modifier key tests (alt, pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: 16 },
+ vertical: { expected: true, preventDefault: true, detail: 16 } },
+ },
+ { description: "modifier key tests (alt, line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: true, detail: gLineHeight } },
+ },
+ { description: "modifier key tests without content checking mode (alt, line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ skipDeltaModeCheck: true,
+ deltaX: SpecialPowers.getIntPref("dom.event.wheel-deltaMode-lines-to-pixel-scale"),
+ deltaY: SpecialPowers.getIntPref("dom.event.wheel-deltaMode-lines-to-pixel-scale"),
+ deltaZ: SpecialPowers.getIntPref("dom.event.wheel-deltaMode-lines-to-pixel-scale"),
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: true, detail: gLineHeight } },
+ },
+ { description: "modifier key tests (alt, page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: true, detail: gPageHeight } },
+ },
+
+ { description: "modifier key tests (meta, pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: true },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: 16 },
+ vertical: { expected: true, preventDefault: true, detail: 16 } },
+ },
+ { description: "modifier key tests (meta, line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: true },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: true, detail: gLineHeight } },
+ },
+ { description: "modifier key tests (meta, page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: true,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: true, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: true, detail: gPageHeight } },
+ },
+
+ // Momentum scroll should cause legacy events.
+ { description: "Momentum scroll should cause legacy events (pixel, not momentum)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 16 },
+ vertical: { expected: true, preventDefault: false, detail: 16 } },
+ },
+ { description: "Momentum scroll should cause legacy events (pixel, momentum)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0, isMomentum: true,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 16.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 16 },
+ vertical: { expected: true, preventDefault: false, detail: 16 } },
+ },
+ { description: "Momentum scroll should cause legacy events (line, not momentum)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: false, detail: gLineHeight } },
+ },
+ { description: "Momentum scroll should cause legacy events (line, momentum)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: true,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gHorizontalLine },
+ vertical: { expected: true, preventDefault: false, detail: gLineHeight } },
+ },
+ { description: "Momentum scroll should cause legacy events (page, not momentum)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: false,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: false, detail: gPageHeight } },
+ },
+ { description: "Momentum scroll should cause legacy events (page, momentum)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, isMomentum: true,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: gPageWidth },
+ vertical: { expected: true, preventDefault: false, detail: gPageHeight } },
+ },
+
+ // Tests for accumulation delta when delta_multiplier_is customized.
+ { description: "lineOrPageDelta should be recomputed by ESM (pixel) #1",
+ prepare () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 200],
+ ["mousewheel.default.delta_multiplier_y", 300]]},
+ continueTest);
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: gHorizontalLine / 4, deltaY: gLineHeight / 8, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: gHorizontalLine / 4 * 2, deltaY: gLineHeight / 8 * 3, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine / 4 * 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight / 8 * 3) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (pixel) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: gHorizontalLine / 4 + 1, deltaY: gLineHeight / 8 + 1, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: (gHorizontalLine / 4 + 1) * 2, deltaY: (gLineHeight / 8 + 1) * 3, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor((gHorizontalLine / 4 + 1) * 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor((gLineHeight / 8 + 1) * 3) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (pixel) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: gHorizontalLine / 4 + 1, deltaY: gLineHeight / 8 + 1, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: (gHorizontalLine / 4 + 1) * 2, deltaY: (gLineHeight / 8 + 1) * 3, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor((gHorizontalLine / 4 + 1) * 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor((gLineHeight / 8 + 1) * 3) } },
+ finished () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
+ },
+ },
+
+ { description: "lineOrPageDelta should be recomputed by ESM (pixel, negative, shift) #1",
+ prepare () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.with_shift.delta_multiplier_x", 200],
+ ["mousewheel.with_shift.delta_multiplier_y", 300]]},
+ continueTest);
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -gHorizontalLine / 4, deltaY: -gLineHeight / 8, deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -gHorizontalLine / 4 * 2, deltaY: -gLineHeight / 8 * 3, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(-gHorizontalLine / 4 * 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.ceil(-gLineHeight / 8 * 3) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (pixel, negative, shift) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -(gHorizontalLine / 4 + 1), deltaY: -(gLineHeight / 8 + 1), deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -(gHorizontalLine / 4 + 1) * 2, deltaY: -(gLineHeight / 8 + 1) * 3, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(-(gHorizontalLine / 4 + 1) * 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.ceil(-(gLineHeight / 8 + 1) * 3) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (pixel, negative, shift) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -(gHorizontalLine / 4 + 1), deltaY: -(gLineHeight / 8 + 1), deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -(gHorizontalLine / 4 + 1) * 2, deltaY: -(gLineHeight / 8 + 1) * 3, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: -1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(-(gHorizontalLine / 4 + 1) * 2) },
+ vertical: { expected: true, preventDefault: false, detail: Math.ceil(-(gLineHeight / 8 + 1) * 3) } },
+ finished () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.with_shift.delta_multiplier_x", 100],
+ ["mousewheel.with_shift.delta_multiplier_y", 100]]},
+ continueTest);
+ },
+ },
+
+ { description: "lineOrPageDelta should be recomputed by ESM (line) #1",
+ prepare () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 200],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.3, deltaY: 0.4, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.6, deltaY: 0.4, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine * 0.6) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (line) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.3, deltaY: 0.4, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.6, deltaY: 0.4, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: 1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine * 0.6) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (line) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.3, deltaY: 0.4, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.6, deltaY: 0.4, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gHorizontalLine * 0.6) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
+ finished () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
+ },
+ },
+
+ { description: "lineOrPageDelta should be recomputed by ESM (line, negative) #1",
+ prepare () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 200],
+ ["mousewheel.default.delta_multiplier_y", -100]]},
+ continueTest);
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.3, deltaY: -0.4, deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -0.6, deltaY: 0.4, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gHorizontalLine * -0.6) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (line, negative) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.3, deltaY: -0.4, deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -0.6, deltaY: 0.4, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: -1 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gHorizontalLine * -0.6) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (line, negative) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.3, deltaY: -0.4, deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -0.6, deltaY: 0.4, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: 1 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gHorizontalLine * -0.6) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gLineHeight * 0.4) } },
+ finished () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
+ },
+ },
+
+ { description: "lineOrPageDelta should be recomputed by ESM (page) #1",
+ prepare () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 200]]},
+ continueTest);
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.3, deltaY: 0.4, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.3, deltaY: 0.8, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth * 0.3) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight * 0.8) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (page) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.3, deltaY: 0.4, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.3, deltaY: 0.8, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth * 0.3) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight * 0.8) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (page) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.4, deltaY: 0.4, deltaZ: 0,
+ lineOrPageDeltaX: 3, lineOrPageDeltaY: 5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: 0.4, deltaY: 0.8, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.floor(gPageWidth * 0.4) },
+ vertical: { expected: true, preventDefault: false, detail: Math.floor(gPageHeight * 0.8) } },
+ finished () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
+ },
+ },
+
+ { description: "lineOrPageDelta should be recomputed by ESM (page, negative) #1",
+ prepare () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 200]]},
+ continueTest);
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.3, deltaY: -0.4, deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -0.3, deltaY: -0.8, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: false, preventDefault: false, detail: 0 } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gPageWidth * -0.3) },
+ vertical: { expected: true, preventDefault: false, detail: Math.ceil(gPageHeight * -0.8) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (page, negative) #2",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.3, deltaY: -0.4, deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -0.3, deltaY: -0.8, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: false, preventDefault: false, detail: 0 },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gPageWidth * -0.3) },
+ vertical: { expected: true, preventDefault: false, detail: Math.ceil(gPageHeight * -0.8) } },
+ },
+ { description: "lineOrPageDelta should be recomputed by ESM (page, negative) #3",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.4, deltaY: -0.4, deltaZ: 0,
+ lineOrPageDeltaX: -3, lineOrPageDeltaY: -5, isNoLineOrPageDelta: false,
+ isCustomizedByPrefs: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+ wheel: {
+ expected: true, preventDefault: false,
+ deltaX: -0.4, deltaY: -0.8, deltaZ: 0
+ },
+ DOMMouseScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP },
+ vertical: { expected: true, preventDefault: false, detail: UIEvent.SCROLL_PAGE_UP } },
+ MozMousePixelScroll: {
+ horizontal: { expected: true, preventDefault: false, detail: Math.ceil(gPageWidth * -0.4) },
+ vertical: { expected: true, preventDefault: false, detail: Math.ceil(gPageHeight * -0.8) } },
+ finished () {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100]]},
+ continueTest);
+ },
+ },
+ ];
+
+ var currentWheelEventTest;
+ var calledHandlers = { wheel: false,
+ DOMMouseScroll: { horizontal: false, vertical: false },
+ MozMousePixelScroll: { horizontal: false, vertical: false } };
+
+ function wheelEventHandler(aEvent)
+ {
+ var description = "testContinuousTrustedEvents, ";
+ description += currentWheelEventTest.description + ": wheel event ";
+
+ ok(!calledHandlers.wheel,
+ description + "was fired twice or more");
+ calledHandlers.wheel = true;
+
+ is(aEvent.target, gScrolledElement,
+ description + "target was invalid");
+ if (!currentWheelEventTest.wheel.skipDeltaModeCheck) {
+ is(aEvent.deltaMode, currentWheelEventTest.event.deltaMode,
+ description + "deltaMode was invalid");
+ }
+ is(SpecialPowers.wrap(aEvent).deltaMode, currentWheelEventTest.event.deltaMode,
+ description + "deltaMode is raw value from privileged script");
+ for (let prop of ["deltaX", "deltaY", "deltaZ"]) {
+ is(aEvent[prop], currentWheelEventTest.wheel[prop],
+ description + prop + " was invalid");
+ if (currentWheelEventTest.wheel.skipDeltaModeCheck) {
+ is(aEvent.deltaMode, WheelEvent.DOM_DELTA_PIXEL,
+ description + "deltaMode should become pixels for line scrolling if unchecked by content")
+ if (aEvent[prop] != 0) {
+ isnot(aEvent[prop], SpecialPowers.wrap(aEvent)[prop],
+ description + "should keep returning raw value for privileged script");
+ }
+ }
+ }
+ is(aEvent.shiftKey, currentWheelEventTest.event.shiftKey,
+ description + "shiftKey was invalid");
+ is(aEvent.ctrlKey, currentWheelEventTest.event.ctrlKey,
+ description + "ctrlKey was invalid");
+ is(aEvent.altKey, currentWheelEventTest.event.altKey,
+ description + "shiftKey was invalid");
+ is(aEvent.metaKey, currentWheelEventTest.event.metaKey,
+ description + "metaKey was invalid");
+
+ ok(!aEvent.defaultPrevented,
+ description + "defaultPrevented should be false");
+ if (currentWheelEventTest.wheel.preventDefault) {
+ aEvent.preventDefault();
+ ok(aEvent.defaultPrevented,
+ description + "defaultPrevented should be true");
+ }
+ }
+
+ function legacyEventHandler(aEvent)
+ {
+ var description = "testContinuousTrustedEvents, ";
+ description += currentWheelEventTest.description + ": " + aEvent.type + " event ";
+
+ if (aEvent.axis != MouseScrollEvent.HORIZONTAL_AXIS &&
+ aEvent.axis != MouseScrollEvent.VERTICAL_AXIS) {
+ ok(false,
+ description + "had invalid axis (" + aEvent.axis + ")");
+ return;
+ }
+
+ var isHorizontal = (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS);
+
+ description += isHorizontal ? "(horizontal) " : "(vertical) ";
+
+ var isScrollEvent = (aEvent.type == "DOMMouseScroll");
+ var expectedEvent =
+ isScrollEvent ? currentWheelEventTest.DOMMouseScroll :
+ currentWheelEventTest.MozMousePixelScroll;
+ var expected =
+ isHorizontal ? expectedEvent.horizontal : expectedEvent.vertical;
+
+ if (aEvent.type == "DOMMouseScroll") {
+ if (isHorizontal) {
+ ok(!calledHandlers.DOMMouseScroll.horizontal,
+ description + "was fired twice or more");
+ calledHandlers.DOMMouseScroll.horizontal = true;
+ } else {
+ ok(!calledHandlers.DOMMouseScroll.vertical,
+ description + "was fired twice or more");
+ calledHandlers.DOMMouseScroll.vertical = true;
+ }
+ } else {
+ if (isHorizontal) {
+ ok(!calledHandlers.MozMousePixelScroll.horizontal,
+ description + "was fired twice or more");
+ calledHandlers.MozMousePixelScroll.horizontal = true;
+ } else {
+ ok(!calledHandlers.MozMousePixelScroll.vertical,
+ description + "was fired twice or more");
+ calledHandlers.MozMousePixelScroll.vertical = true;
+ }
+ }
+
+ is(aEvent.target, gScrolledElement,
+ description + "target was invalid");
+ is(aEvent.detail, expected.detail,
+ description + "detail was invalid");
+
+ is(aEvent.shiftKey, currentWheelEventTest.event.shiftKey,
+ description + "shiftKey was invalid");
+ is(aEvent.ctrlKey, currentWheelEventTest.event.ctrlKey,
+ description + "ctrlKey was invalid");
+ is(aEvent.altKey, currentWheelEventTest.event.altKey,
+ description + "shiftKey was invalid");
+ is(aEvent.metaKey, currentWheelEventTest.event.metaKey,
+ description + "metaKey was invalid");
+
+ var expectedDefaultPrevented =
+ isScrollEvent ? false :
+ isHorizontal ? currentWheelEventTest.DOMMouseScroll.horizontal.preventDefault :
+ currentWheelEventTest.DOMMouseScroll.vertical.preventDefault;
+ is(aEvent.defaultPrevented, expectedDefaultPrevented,
+ description + "defaultPrevented should be " + expectedDefaultPrevented);
+
+ if (expected.preventDefault) {
+ aEvent.preventDefault();
+ ok(aEvent.defaultPrevented,
+ description + "defaultPrevented should be true");
+ }
+ }
+
+ window.addEventListener("wheel", wheelEventHandler, { capture: true, passive: false });
+ window.addEventListener("DOMMouseScroll", legacyEventHandler, { capture: true, passive: false });
+ window.addEventListener("MozMousePixelScroll", legacyEventHandler, { capture: true, passive: false });
+
+ for (var i = 0; i < kSynthesizedWheelEventTests.length; i++) {
+ gScrollableElement.scrollTop = gScrollableElement.scrollBottom = 1000;
+
+ currentWheelEventTest = kSynthesizedWheelEventTests[i];
+
+ if (currentWheelEventTest.prepare) {
+ yield currentWheelEventTest.prepare();
+ }
+
+ yield sendWheelAndWait(10, 10, currentWheelEventTest.event);
+
+ if (currentWheelEventTest.finished) {
+ yield currentWheelEventTest.finished();
+ }
+
+ var description = "testContinuousTrustedEvents, " +
+ currentWheelEventTest.description + ": ";
+ is(calledHandlers.wheel, currentWheelEventTest.wheel.expected,
+ description + "wheel event was fired or not fired");
+ is(calledHandlers.DOMMouseScroll.horizontal,
+ currentWheelEventTest.DOMMouseScroll.horizontal.expected,
+ description + "horizontal DOMMouseScroll event was fired or not fired");
+ is(calledHandlers.DOMMouseScroll.vertical,
+ currentWheelEventTest.DOMMouseScroll.vertical.expected,
+ description + "vertical DOMMouseScroll event was fired or not fired");
+ is(calledHandlers.MozMousePixelScroll.horizontal,
+ currentWheelEventTest.MozMousePixelScroll.horizontal.expected,
+ description + "horizontal MozMousePixelScroll event was fired or not fired");
+ is(calledHandlers.MozMousePixelScroll.vertical,
+ currentWheelEventTest.MozMousePixelScroll.vertical.expected,
+ description + "vertical MozMousePixelScroll event was fired or not fired");
+
+ calledHandlers = { wheel: false,
+ DOMMouseScroll: { horizontal: false, vertical: false },
+ MozMousePixelScroll: { horizontal: false, vertical: false } };
+ }
+
+ window.removeEventListener("wheel", wheelEventHandler, true);
+ window.removeEventListener("DOMMouseScroll", legacyEventHandler, true);
+ window.removeEventListener("MozMousePixelScroll", legacyEventHandler, true);
+}
+
+var gTestContinuation = null;
+
+function continueTest()
+{
+ if (!gTestContinuation) {
+ gTestContinuation = testBody();
+ }
+ var ret = gTestContinuation.next();
+ if (ret.done) {
+ SimpleTest.finish();
+ }
+}
+
+function* testBody()
+{
+ yield* prepareScrollUnits();
+ yield* testContinuousTrustedEvents();
+}
+
+function runTests()
+{
+ SpecialPowers.pushPrefEnv({"set": [
+ // FIXME(emilio): This test is broken in HiDPI, unclear if
+ // MozMousePixelScroll is not properly converting to CSS pixels, or
+ // whether sendWheelAndWait expectes device rather than CSS pixels, or
+ // something else.
+ ["layout.css.devPixelsPerPx", 1.0],
+
+ ["dom.event.wheel-deltaMode-lines.disabled", true],
+
+ ["mousewheel.transaction.timeout", 100000],
+ ["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100],
+ ["mousewheel.default.delta_multiplier_z", 100],
+ ["mousewheel.with_alt.delta_multiplier_x", 100],
+ ["mousewheel.with_alt.delta_multiplier_y", 100],
+ ["mousewheel.with_alt.delta_multiplier_z", 100],
+ ["mousewheel.with_control.delta_multiplier_x", 100],
+ ["mousewheel.with_control.delta_multiplier_y", 100],
+ ["mousewheel.with_control.delta_multiplier_z", 100],
+ ["mousewheel.with_meta.delta_multiplier_x", 100],
+ ["mousewheel.with_meta.delta_multiplier_y", 100],
+ ["mousewheel.with_meta.delta_multiplier_z", 100],
+ ["mousewheel.with_shift.delta_multiplier_x", 100],
+ ["mousewheel.with_shift.delta_multiplier_y", 100],
+ ["mousewheel.with_shift.delta_multiplier_z", 100],
+ ["mousewheel.with_win.delta_multiplier_x", 100],
+ ["mousewheel.with_win.delta_multiplier_y", 100],
+ ["mousewheel.with_win.delta_multiplier_z", 100]
+ ]}, continueTest);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_dblclick_explicit_original_target.html b/dom/events/test/test_dblclick_explicit_original_target.html
new file mode 100644
index 0000000000..214ae48dea
--- /dev/null
+++ b/dom/events/test/test_dblclick_explicit_original_target.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test explicit original target of dblclick event</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display">Test explicit original target of dblclick event</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests);
+
+function runTests()
+{
+ synthesizeMouse(document.getElementById("display"), 5, 5, { clickCount: 2 });
+}
+
+window.onmousedown = function(event) {
+ is(event.explicitOriginalTarget.nodeType, Node.TEXT_NODE,
+ "explicitOriginalTarget is a text node");
+ is(event.explicitOriginalTarget, document.getElementById("display").firstChild,
+ "explicitOriginalTarget should point to the child node of the click target");
+}
+
+window.onmouseup = function(event) {
+ is(event.explicitOriginalTarget.nodeType, Node.TEXT_NODE,
+ "explicitOriginalTarget is a text node");
+ is(event.explicitOriginalTarget, document.getElementById("display").firstChild,
+ "explicitOriginalTarget should point to the child node of the click target");
+}
+
+// The old versions of Gecko had explicitOriginalTarget pointing to a Text node
+// when handling *click events, newer versions target Elements.
+window.ondblclick = function(event) {
+ is(event.explicitOriginalTarget.nodeType, Node.ELEMENT_NODE,
+ "explicitOriginalTarget is an element node");
+ is(event.explicitOriginalTarget, document.getElementById("display"),
+ "explicitOriginalTarget should point to the click target");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_deviceSensor.html b/dom/events/test/test_deviceSensor.html
new file mode 100644
index 0000000000..f4ce658298
--- /dev/null
+++ b/dom/events/test/test_deviceSensor.html
@@ -0,0 +1,136 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=402089
+-->
+<head>
+ <title>Test for Bug 742376</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=742376">Mozilla Bug 742376</a>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 742376 **/
+let Cc = SpecialPowers.Cc;
+let Ci = SpecialPowers.Ci;
+let dss = Cc["@mozilla.org/devicesensors;1"].getService(Ci.nsIDeviceSensors);
+
+function hasLightListeners() {
+ return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_LIGHT, window);
+}
+
+function hasOrientationListeners() {
+ return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ORIENTATION, window) ||
+ dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ROTATION_VECTOR, window) ||
+ dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_GAME_ROTATION_VECTOR, window);
+}
+
+function hasProximityListeners() {
+ return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_PROXIMITY, window);
+}
+
+function hasMotionListeners() {
+ return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ACCELERATION, window) ||
+ dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_LINEAR_ACCELERATION, window) ||
+ dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_GYROSCOPE, window);
+}
+
+async function test_event_presence(prefName, eventCheck, eventName) {
+ function dumbListener(event) {}
+ function dumbListener2(event) {}
+ function dumbListener3(event) {}
+
+ await SpecialPowers.pushPrefEnv({"set": [
+ [prefName, true]
+ ]});
+
+ is(eventCheck(), false, "Must not have listeners before tests start");
+
+ window.addEventListener(eventName, dumbListener);
+ window.addEventListener("random_event_name", function() {});
+ window.addEventListener(eventName, dumbListener2);
+
+ is(eventCheck(), true, `Should have listeners when ${eventName} sensor is enabled`);
+
+ window.removeEventListener(eventName, dumbListener);
+ window.removeEventListener(eventName, dumbListener2);
+
+ is(eventCheck(), false, "Must not have listeners when removed");
+
+ await SpecialPowers.pushPrefEnv({"set": [
+ [prefName, false]
+ ]});
+
+ window.addEventListener(eventName, dumbListener);
+ window.addEventListener("random_event_name", function() {});
+ window.addEventListener(eventName, dumbListener2);
+
+ is(eventCheck(), false, "Must not have listeners when sensor is disabled");
+}
+
+async function start() {
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["device.sensors.enabled", true],
+ ["device.sensors.orientation.enabled", true]
+ ]});
+
+ is(hasOrientationListeners(), false, "Must not have listeners before tests start");
+
+ function dumbListener(event) {}
+ function dumbListener2(event) {}
+ function dumbListener3(event) {}
+
+ window.addEventListener("deviceorientation", dumbListener);
+ window.addEventListener("random_event_name", function() {});
+ window.addEventListener("deviceorientation", dumbListener2);
+
+ is(hasOrientationListeners(), true, "Listeners should have been added");
+
+ await new Promise(resolve => {
+ window.setTimeout(function() {
+ window.removeEventListener("deviceorientation", dumbListener);
+ is(hasOrientationListeners(), true, "Only some listeners should have been removed");
+ window.setTimeout(function() {
+ window.removeEventListener("deviceorientation", dumbListener2);
+ window.setTimeout(function() {
+ is(hasOrientationListeners(), false, "Listeners should have been removed");
+ resolve();
+ }, 0);
+ }, 0);
+ }, 0);
+ });
+
+ await new Promise(resolve => {
+ window.ondeviceorientation = function() {}
+ window.setTimeout(function() {
+ is(hasOrientationListeners(), true, "Handler should have been added");
+ window.ondeviceorientation = null;
+ window.setTimeout(function() {
+ is(hasOrientationListeners(), false, "Handler should have been removed");
+ resolve();
+ }, 0);
+ }, 0);
+ });
+
+ await test_event_presence("device.sensors.ambientLight.enabled", hasLightListeners, "devicelight");
+ await test_event_presence("device.sensors.proximity.enabled", hasProximityListeners, "deviceproximity");
+ await test_event_presence("device.sensors.motion.enabled", hasMotionListeners, "devicemotion");
+ await test_event_presence("device.sensors.orientation.enabled", hasOrientationListeners, "deviceorientation");
+
+ SimpleTest.finish();
+
+}
+
+SimpleTest.waitForExplicitFinish();
+
+start();
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/events/test/test_disabled_events.html b/dom/events/test/test_disabled_events.html
new file mode 100644
index 0000000000..d19b021fe8
--- /dev/null
+++ b/dom/events/test/test_disabled_events.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1359076
+-->
+<head>
+ <title>Test for Bug 675884</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1359076">Mozilla Bug 1359076</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [
+ ["device.sensors.orientation.enabled", false],
+ ["device.sensors.motion.enabled", false],
+ ["device.sensors.proximity.enabled", false],
+ ["device.sensors.ambientLight.enabled", false],
+ ["dom.w3c_pointer_events.enabled", false]
+]}, () => {
+ is("DeviceProximityEvent" in window, false, "DeviceProximityEvent does not exist");
+ is("UserProximityEvent" in window, false, "UserProximityEvent does not exist");
+ is("DeviceLightEvent" in window, false, "DeviceLightEvent does not exist");
+ is("DeviceOrientationEvent" in window, false, "DeviceOrientationEvent does not exist");
+ is("DeviceMotionEvent" in window, false, "DeviceMotionEvent does not exist");
+ SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_dnd_with_modifiers.html b/dom/events/test/test_dnd_with_modifiers.html
new file mode 100644
index 0000000000..8b861c9306
--- /dev/null
+++ b/dom/events/test/test_dnd_with_modifiers.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8">
+ <title>Test dragstart, drag, dragover, drop, dragend with keyboard modifiers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+ <div id="test"></div>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ SimpleTest.waitForFocus(() => {
+ let dragEvents = ["dragstart", "drag", "dragend"];
+ let dropEvents = ["dragover", "drop"];
+ let source = document.getElementById("source");
+ let target = document.getElementById("target");
+
+ dragEvents.forEach((ev, idx, array) => {
+ source.addEventListener(ev, (e) => {
+ ok(e.ctrlKey, e.type + ".ctrlKey should be true");
+ ok(!e.shiftKey, e.type + ".shiftKey should be false");
+ ok(e.altKey, e.type + ".altKey should be true");
+ }, {once: true});
+ });
+
+ dropEvents.forEach((ev, idx, array) => {
+ target.addEventListener(ev, (e) => {
+ ok(e.ctrlKey, e.type + ".ctrlKey should be true");
+ ok(!e.shiftKey, e.type + ".shiftKey should be false");
+ ok(e.altKey, e.type + ".altKey should be true");
+ }, {once: true});
+ });
+
+ source.addEventListener("dragstart", (e) => {
+ e.preventDefault();
+ }, {once: true});
+
+ source.addEventListener("dragend", (e) => {
+ SimpleTest.finish();
+ });
+
+ let selection = window.getSelection();
+ selection.selectAllChildren(source);
+
+ synthesizeMouse(source, 1, 1, {type: "mousedown", ctrlKey: true, altKey: true}, window);
+ synthesizeMouse(source, 10, 10, {type: "mousemove", ctrlKey: true, altKey: true}, window);
+ synthesizeMouse(source, 10, 10, {type: "mouseup", ctrlKey: true, altKey: true}, window);
+
+ let dragEvent = {
+ type: "drag",
+ ctrlKey: true,
+ altKey: true,
+ };
+ sendDragEvent(dragEvent, source, window);
+
+ let rect = target.getBoundingClientRect();
+ let dropEvent = {
+ ctrlKey: true,
+ altKey: true,
+ clientX: rect.left + rect.width / 2,
+ clientY: rect.top + rect.height / 2,
+ };
+ selection.selectAllChildren(source);
+ synthesizeDrop(source, target, [], "copy", window, window, dropEvent);
+
+ let dragEndEvent = {
+ type: "dragend",
+ ctrlKey: true,
+ altKey: true,
+ };
+ sendDragEvent(dragEndEvent, source, window);
+ });
+ </script>
+<body>
+ <span id="source" style="font-size: 40px;">test</span>
+ <div id="target" contenteditable="true" width="50" height="50"></div>
+</body>
+</html>
diff --git a/dom/events/test/test_dom_activate_event.html b/dom/events/test/test_dom_activate_event.html
new file mode 100644
index 0000000000..9a6d48ac64
--- /dev/null
+++ b/dom/events/test/test_dom_activate_event.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test DOMActivate event</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display">
+<a id="a" href="#dummy">link</a>
+<button id="button">button</button>
+<input id="checkbox" type="checkbox">
+<input id="radio" type="radio">
+<input id="submit" type="submit">
+<input id="ibutton" type="button">
+<input id="reset" type="reset">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/* eslint-disable max-nested-callbacks */
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests);
+
+function runIsTrustedTestCausedByTrustedClick(aElement, aNextTest)
+{
+ const kDescription = "runIsTrustedTestCausedByTrustedClick(aElement.id=" + aElement.id + "): ";
+ var DOMActivateFired = false;
+ aElement.addEventListener("DOMActivate", function (aEvent) {
+ DOMActivateFired = true;
+ ok(aEvent.isTrusted, kDescription + "DOMActivate event should be trusted event");
+ aElement.removeEventListener("DOMActivate", arguments.callee);
+ aNextTest();
+ });
+ aElement.addEventListener("click", function (aEvent) {
+ ok(aEvent.isTrusted, kDescription + "click event should be trusted event");
+ aElement.removeEventListener("click", arguments.callee);
+ });
+ synthesizeMouseAtCenter(aElement, {});
+}
+
+function runIsTrustedTestCausedByUntrustedClick(aElement, aNextTest)
+{
+ const kDescription = "runIsTrustedTestCausedByUntrustedClick(aElement.id=" + aElement.id + "): ";
+ var DOMActivateFired = false;
+ aElement.addEventListener("DOMActivate", function (aEvent) {
+ DOMActivateFired = true;
+ ok(aEvent.isTrusted,
+ kDescription + "DOMActivate event should be trusted event even if it's caused by untrusted event");
+ aElement.removeEventListener("DOMActivate", arguments.callee);
+ aNextTest();
+ });
+ aElement.addEventListener("click", function (aEvent) {
+ ok(!aEvent.isTrusted, kDescription + "click event should be untrusted event");
+ aElement.removeEventListener("click", arguments.callee);
+ });
+ var click = new MouseEvent("click", { button: 0 });
+ aElement.dispatchEvent(click);
+}
+
+function runTests()
+{
+ // XXX Don't add indentation here. If you add indentation, the diff will be
+ // complicated when somebody adds new tests.
+ runIsTrustedTestCausedByTrustedClick(document.getElementById("a"), function () {
+ runIsTrustedTestCausedByTrustedClick(document.getElementById("button"), function () {
+ runIsTrustedTestCausedByTrustedClick(document.getElementById("checkbox"), function () {
+ runIsTrustedTestCausedByTrustedClick(document.getElementById("radio"), function () {
+ runIsTrustedTestCausedByTrustedClick(document.getElementById("submit"), function () {
+ runIsTrustedTestCausedByTrustedClick(document.getElementById("ibutton"), function () {
+ runIsTrustedTestCausedByTrustedClick(document.getElementById("reset"), function () {
+ runIsTrustedTestCausedByUntrustedClick(document.getElementById("a"), function () {
+ runIsTrustedTestCausedByUntrustedClick(document.getElementById("button"), function () {
+ runIsTrustedTestCausedByUntrustedClick(document.getElementById("checkbox"), function () {
+ runIsTrustedTestCausedByUntrustedClick(document.getElementById("radio"), function () {
+ runIsTrustedTestCausedByUntrustedClick(document.getElementById("submit"), function () {
+ runIsTrustedTestCausedByUntrustedClick(document.getElementById("ibutton"), function () {
+ runIsTrustedTestCausedByUntrustedClick(document.getElementById("reset"), function () {
+ SimpleTest.finish();
+ });});});});});});});});});});});});});});
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_dom_keyboard_event.html b/dom/events/test/test_dom_keyboard_event.html
new file mode 100644
index 0000000000..2c8670d263
--- /dev/null
+++ b/dom/events/test/test_dom_keyboard_event.html
@@ -0,0 +1,548 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for DOM KeyboardEvent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<p><input type="text" id="input"></p>
+<p><input type="text" id="input_readonly" readonly></p>
+<p><textarea id="textarea"></textarea></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests, window);
+
+const kStrictKeyPressEvents =
+ SpecialPowers.getBoolPref("dom.keyboardevent.keypress.dispatch_non_printable_keys_only_system_group_in_content");
+const kBeforeinputEventEnabled =
+ SpecialPowers.getBoolPref("dom.input_events.beforeinput.enabled");
+
+function testInitializingUntrustedEvent()
+{
+ const kTests = [
+ // initKeyEvent
+ { createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
+ type: "keydown", bubbles: true, cancelable: true, view: null,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+ keyCode: 0x00, charCode: 0x00, detail: 0, key: "", location: 0,
+ }, // 0
+
+ { createEventArg: "keyboardevent", useInitKeyboardEvent: false,
+ type: "keyup", bubbles: false, cancelable: true, view: window,
+ ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
+ keyCode: 0x10, charCode: 0x00, detail: 0, key: "", location: 0,
+ }, // 1
+
+ { createEventArg: "Keyboardevent", useInitKeyboardEvent: false,
+ type: "keypress", bubbles: true, cancelable: false, view: null,
+ ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
+ keyCode: 0x11, charCode: 0x30, detail: 0, key: "", location: 0,
+ }, // 2
+
+ { createEventArg: "keyboardEvent", useInitKeyboardEvent: false,
+ type: "boo", bubbles: false, cancelable: false, view: window,
+ ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
+ keyCode: 0x30, charCode: 0x40, detail: 0, key: "", location: 0,
+ }, // 3
+
+ { createEventArg: "KeyBoardEvent", useInitKeyboardEvent: false,
+ type: "foo", bubbles: true, cancelable: true, view: null,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
+ keyCode: 0x00, charCode: 0x50, detail: 0, key: "", location: 0,
+ }, // 4
+
+ { createEventArg: "keyboardevEnt", useInitKeyboardEvent: false,
+ type: "bar", bubbles: false, cancelable: true, view: window,
+ ctrlKey: true, altKey: true, shiftKey: false, metaKey: false,
+ keyCode: 0x00, charCode: 0x60, detail: 0, key: "", location: 0,
+ }, // 5
+
+ { createEventArg: "KeyboaRdevent", useInitKeyboardEvent: false,
+ type: "keydown", bubbles: true, cancelable: false, view: null,
+ ctrlKey: false, altKey: true, shiftKey: false, metaKey: true,
+ keyCode: 0x30, charCode: 0x00, detail: 0, key: "", location: 0,
+ }, // 6
+
+ { createEventArg: "KEYBOARDEVENT", useInitKeyboardEvent: false,
+ type: "keyup", bubbles: false, cancelable: false, view: window,
+ ctrlKey: true, altKey: false, shiftKey: true, metaKey: false,
+ keyCode: 0x10, charCode: 0x80, detail: 0, key: "", location: 0,
+ }, // 7
+
+ { createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
+ type: "keypress", bubbles: false, cancelable: false, view: window,
+ ctrlKey: true, altKey: false, shiftKey: true, metaKey: true,
+ keyCode: 0x10, charCode: 0x80, detail: 0, key: "", location: 0,
+ }, // 8
+
+ { createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
+ type: "foo", bubbles: false, cancelable: false, view: window,
+ ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
+ keyCode: 0x10, charCode: 0x80, detail: 0, key: "", location: 0,
+ }, // 9
+
+ // initKeyboardEvent
+ { createEventArg: "KeyboardEvent", useInitKeyboardEvent: true,
+ type: "keydown", bubbles: true, cancelable: true, view: null,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+ keyCode: 0x00, charCode: 0x00, key: "", location: 0,
+ }, // 10
+
+ { createEventArg: "keyboardevent", useInitKeyboardEvent: true,
+ type: "keyup", bubbles: false, cancelable: true, view: window,
+ ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
+ keyCode: 0x00, charCode: 0x00, key: "Unidentified", location: 1,
+ }, // 11
+
+ { createEventArg: "Keyboardevent", useInitKeyboardEvent: true,
+ type: "keypress", bubbles: true, cancelable: false, view: null,
+ ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
+ keyCode: 0x00, charCode: 0x00, key: "FooBar", location: 2,
+ }, // 12
+
+ { createEventArg: "keyboardevent", useInitKeyboardEvent: true,
+ type: "foo", bubbles: true, cancelable: true, view: null,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
+ keyCode: 0x00, charCode: 0x00, key: "a", location: 0,
+ }, // 13
+
+ { createEventArg: "KeyBoardEvent", useInitKeyboardEvent: true,
+ type: "", bubbles: false, cancelable: false, view: null,
+ ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
+ keyCode: 0x00, charCode: 0x00, key: "3", location: 0,
+ }, // 14
+
+ { createEventArg: "keyboardevEnt", useInitKeyboardEvent: true,
+ type: "", bubbles: false, cancelable: false, view: null,
+ ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
+ keyCode: 0x00, charCode: 0x00, key: "3", location: 6,
+ }, // 15
+
+ { createEventArg: "KeyboaRdevent", useInitKeyboardEvent: true,
+ type: "", bubbles: false, cancelable: false, view: null,
+ ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
+ keyCode: 0x00, charCode: 0x00, key: "", location: 4,
+ }, // 16
+ ];
+
+ const kOtherModifierName = [
+ "CapsLock", "NumLock", "ScrollLock", "Symbol", "SymbolLock", "Fn", "FnLock", "OS", "AltGraph"
+ ];
+
+ const kInvalidModifierName = [
+ "shift", "control", "alt", "meta", "capslock", "numlock", "scrolllock",
+ "symbollock", "fn", "os", "altgraph", "Invalid", "Shift Control",
+ "Win", "Scroll"
+ ];
+
+ for (var i = 0; i < kTests.length; i++) {
+ var description = "testInitializingUntrustedEvent, Index: " + i + ", ";
+ const kTest = kTests[i];
+ var e = document.createEvent(kTest.createEventArg);
+ if (kTest.useInitKeyboardEvent) {
+ e.initKeyboardEvent(kTest.type, kTest.bubbles, kTest.cancelable,
+ kTest.view, kTest.key, kTest.location,
+ kTest.ctrlKey, kTest.altKey, kTest.shiftKey,
+ kTest.metaKey);
+ } else {
+ e.initKeyEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view,
+ kTest.ctrlKey, kTest.altKey, kTest.shiftKey, kTest.metaKey,
+ kTest.keyCode, kTest.charCode);
+ }
+ is(e.toString(), "[object KeyboardEvent]",
+ description + 'class string should be "KeyboardEvent"');
+
+ for (var attr in kTest) {
+ if (attr == "createEventArg" || attr == "useInitKeyboardEvent" || attr == "modifiersList") {
+ continue;
+ }
+ if (!kTest.useInitKeyboardEvent && attr == "keyCode") {
+ // If this is keydown, keyup of keypress event, keycod must be correct.
+ if (kTest.type == "keydown" || kTest.type == "keyup" || kTest.type == "keypress") {
+ is(e[attr], kTest[attr], description + attr + " returns wrong value");
+ // Otherwise, should be always zero (why?)
+ } else {
+ is(e[attr], 0, description + attr + " returns non-zero for invalid event");
+ }
+ } else if (!kTest.useInitKeyboardEvent && attr == "charCode") {
+ // If this is keydown or keyup event, charCode always 0.
+ if (kTest.type == "keydown" || kTest.type == "keyup") {
+ is(e[attr], 0, description + attr + " returns non-zero for keydown or keyup event");
+ // If this is keypress event, charCode must be correct.
+ } else if (kTest.type == "keypress") {
+ is(e[attr], kTest[attr], description + attr + " returns wrong value");
+ // Otherwise, we have a bug.
+ } else {
+ if (e[attr] != kTest[attr]) { // avoid random unexpected pass.
+ todo_is(e[attr], kTest[attr], description + attr + " returns wrong value");
+ }
+ }
+ } else {
+ is(e[attr], kTest[attr], description + attr + " returns wrong value");
+ }
+ }
+ is(e.isTrusted, false, description + "isTrusted returns wrong value");
+
+ // getModifierState() tests
+ is(e.getModifierState("Shift"), kTest.shiftKey,
+ description + "getModifierState(\"Shift\") returns wrong value");
+ is(e.getModifierState("Control"), kTest.ctrlKey,
+ description + "getModifierState(\"Control\") returns wrong value");
+ is(e.getModifierState("Alt"), kTest.altKey,
+ description + "getModifierState(\"Alt\") returns wrong value");
+ is(e.getModifierState("Meta"), kTest.metaKey,
+ description + "getModifierState(\"Meta\") returns wrong value");
+
+ for (var j = 0; j < kOtherModifierName.length; j++) {
+ ok(!e.getModifierState(kOtherModifierName[j]),
+ description + "getModifierState(\"" + kOtherModifierName[j] + "\") returns wrong value");
+ }
+ for (var k = 0; k < kInvalidModifierName.length; k++) {
+ ok(!e.getModifierState(kInvalidModifierName[k]),
+ description + "getModifierState(\"" + kInvalidModifierName[k] + "\") returns wrong value");
+ }
+ }
+}
+
+function testSynthesizedKeyLocation()
+{
+ const kTests = [
+ { key: "a", isModifier: false, isPrintable: true,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_A,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ },
+ { key: "KEY_Shift", isModifier: true, isPrintable: false,
+ event: { shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_SHIFT,
+ location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ },
+ { key: "KEY_Shift", isModifier: true, isPrintable: false,
+ event: { shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_SHIFT,
+ location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ },
+ { key: "KEY_Control", isModifier: true, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_CONTROL,
+ location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ },
+ { key: "KEY_Control", isModifier: true, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_CONTROL,
+ location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ },
+/* XXX Alt key activates menubar even if we consume the key events.
+ { key: "KEY_Alt", isModifier: true, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_ALT,
+ location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ },
+ { key: "KEY_Alt", isModifier: true, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_ALT,
+ location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ },
+*/
+ { key: "KEY_Meta", isModifier: true, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: true, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_META,
+ location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ },
+ { key: "KEY_Meta", isModifier: true, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: true, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_META,
+ location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ },
+ { key: "KEY_ArrowDown", isModifier: false, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_DOWN,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ },
+ { key: "KEY_ArrowDown", isModifier: false, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_DOWN,
+ location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ },
+ { key: "5", isModifier: false, isPrintable: true,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_5,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ },
+ { key: "5", isModifier: false, isPrintable: true,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: true,
+ keyCode: KeyboardEvent.DOM_VK_NUMPAD5,
+ location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ },
+ { key: "+", isModifier: false, isPrintable: true,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_EQUALS,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ },
+ { key: "+", isModifier: false, isPrintable: true,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: true,
+ keyCode: KeyboardEvent.DOM_VK_ADD,
+ location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ },
+ { key: "KEY_Enter", isModifier: false, isPrintable: true,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_RETURN,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ },
+ { key: "KEY_Enter", isModifier: false, isPrintable: true,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_RETURN,
+ location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ },
+ { key: "KEY_NumLock", isModifier: true, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_NUM_LOCK,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ },
+ { key: "KEY_Insert", isModifier: false, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_INSERT,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ },
+ { key: "KEY_Insert", isModifier: false, isPrintable: false,
+ event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, numLockKey: false,
+ keyCode: KeyboardEvent.DOM_VK_INSERT,
+ location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ },
+ ];
+
+ function getLocationName(aLocation)
+ {
+ switch (aLocation) {
+ case KeyboardEvent.DOM_KEY_LOCATION_STANDARD:
+ return "DOM_KEY_LOCATION_STANDARD";
+ case KeyboardEvent.DOM_KEY_LOCATION_LEFT:
+ return "DOM_KEY_LOCATION_LEFT";
+ case KeyboardEvent.DOM_KEY_LOCATION_RIGHT:
+ return "DOM_KEY_LOCATION_RIGHT";
+ case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
+ return "DOM_KEY_LOCATION_NUMPAD";
+ default:
+ return "Invalid value (" + aLocation + ")";
+ }
+ }
+
+ var currentTest, description;
+ var events = { keydown: false, keypress: false, keyup: false };
+
+ function handler(aEvent)
+ {
+ is(aEvent.location, currentTest.event.location,
+ description + "location of " + aEvent.type + " was invalid");
+ events[aEvent.type] = true;
+ if (aEvent.type != "keydown" ||
+ (currentTest.event.isModifier && aEvent.type == "keydown")) {
+ aEvent.preventDefault();
+ }
+ }
+
+ window.addEventListener("keydown", handler, true);
+ window.addEventListener("keypress", handler, true);
+ window.addEventListener("keyup", handler, true);
+
+ for (var i = 0; i < kTests.length; i++) {
+ currentTest = kTests[i];
+ events = { keydown: false, keypress: false, keyup: false };
+ description = "testSynthesizedKeyLocation, " + i + ", key: " +
+ currentTest.key + ", location: " +
+ getLocationName(currentTest.event.location) + ": ";
+ synthesizeKey(currentTest.key, currentTest.event);
+ ok(events.keydown, description + "keydown event wasn't fired");
+ if (kStrictKeyPressEvents) {
+ if (currentTest.isPrintable) {
+ ok(events.keypress, description + "keypress event wasn't fired for printable key");
+ } else {
+ ok(!events.keypress, description + "keypress event was fired for non-printable key");
+ }
+ } else {
+ if (currentTest.isModifier) {
+ todo(events.keypress, description + "keypress event was fired for modifier key");
+ } else {
+ ok(events.keypress, description + "keypress event wasn't fired");
+ }
+ }
+ ok(events.keyup, description + "keyup event wasn't fired");
+ }
+
+ window.removeEventListener("keydown", handler, true);
+ window.removeEventListener("keypress", handler, true);
+ window.removeEventListener("keyup", handler, true);
+}
+
+// We're using TextEventDispatcher to decide if we should keypress event
+// on content in the default event group. So, we can test if keypress
+// event is NOT fired unexpectedly with synthesizeKey().
+function testEnterKeyPressEvent()
+{
+ let keydownFired, keypressFired, beforeinputFired;
+ function onEvent(aEvent) {
+ switch (aEvent.type) {
+ case "keydown":
+ keydownFired = true;
+ return;
+ case "keypress":
+ keypressFired = true;
+ return;
+ case "beforeinput":
+ beforeinputFired = true;
+ return;
+ }
+ }
+
+ for (let targetId of ["input", "textarea", "input_readonly"]) {
+ let target = document.getElementById(targetId);
+
+ function reset() {
+ keydownFired = keypressFired = beforeinputFired = false;
+ target.value = "";
+ }
+
+ target.addEventListener("keydown", onEvent);
+ target.addEventListener("keypress", onEvent);
+ target.addEventListener("beforeinput", onEvent);
+
+ const kDescription = "<" + targetId.replace("_", " ") + ">: ";
+ let isEditable = !kDescription.includes("readonly");
+ let isTextarea = kDescription.includes("textarea");
+
+ target.focus();
+
+ reset();
+ synthesizeKey("KEY_Enter");
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Enter key is pressed");
+ is(keypressFired, true,
+ kDescription + "keypress event should be fired when Enter key is pressed");
+ if (isEditable) {
+ is(beforeinputFired, kBeforeinputEventEnabled,
+ kDescription + "beforeinput event should be fired (if it's enabled) when Enter key is pressed");
+ } else {
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Enter key is pressed");
+ }
+ if (isTextarea) {
+ is(target.value, "\n",
+ kDescription + "Enter key should cause inputting a line break in <textarea>");
+ } else {
+ is(target.value, "",
+ kDescription + "Enter key should not cause inputting a line break");
+ }
+
+ reset();
+ synthesizeKey("KEY_Enter", {shiftKey: true});
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Shift + Enter key is pressed");
+ is(keypressFired, true,
+ kDescription + "keypress event should be fired when Shift + Enter key is pressed");
+ if (isEditable) {
+ is(beforeinputFired, kBeforeinputEventEnabled,
+ kDescription + "beforeinput event should be fired (if it's enabled) when Shift + Enter key is pressed");
+ } else {
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Shift + Enter key is pressed");
+ }
+ if (isTextarea) {
+ is(target.value, "\n",
+ kDescription + "Shift + Enter key should cause inputting a line break in <textarea>");
+ } else {
+ is(target.value, "",
+ kDescription + "Shift + Enter key should not cause inputting a line break");
+ }
+
+ reset();
+ synthesizeKey("KEY_Enter", {ctrlKey: true});
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Ctrl + Enter key is pressed");
+ is(keypressFired, true,
+ kDescription + "keypress event should be fired when Ctrl + Enter key is pressed");
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Ctrl + Enter key is pressed");
+ is(target.value, "",
+ kDescription + "Ctrl + Enter key should not cause inputting a line break");
+
+ reset();
+ synthesizeKey("KEY_Enter", {altKey: true});
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Alt + Enter key is pressed");
+ is(keypressFired, !kStrictKeyPressEvents,
+ kDescription + "keypress event shouldn't be fired when Alt + Enter key is pressed in strict keypress dispatching mode");
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Alt + Enter key is pressed");
+ is(target.value, "",
+ kDescription + "Alt + Enter key should not cause inputting a line break");
+
+ reset();
+ synthesizeKey("KEY_Enter", {metaKey: true});
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Meta + Enter key is pressed");
+ is(keypressFired, !kStrictKeyPressEvents,
+ kDescription + "keypress event shouldn't be fired when Meta + Enter key is pressed in strict keypress dispatching mode");
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Meta + Enter key is pressed");
+ is(target.value, "",
+ kDescription + "Meta + Enter key should not cause inputting a line break");
+
+ reset();
+ synthesizeKey("KEY_Enter", {shiftKey: true, ctrlKey: true});
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Ctrl + Shift + Enter key is pressed");
+ is(keypressFired, !kStrictKeyPressEvents,
+ kDescription + "keypress event shouldn't be fired when Ctrl + Shift + Enter key is pressed in strict keypress dispatching mode");
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Ctrl + Shift + Enter key is pressed");
+ is(target.value, "",
+ kDescription + "Ctrl + Shift + Enter key should not cause inputting a line break");
+
+ reset();
+ synthesizeKey("KEY_Enter", {shiftKey: true, altKey: true});
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Alt + Shift + Enter key is pressed");
+ is(keypressFired, !kStrictKeyPressEvents,
+ kDescription + "keypress event shouldn't be fired when Alt + Shift + Enter key is pressed in strict keypress dispatching mode");
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Alt + Shift + Enter key is pressed");
+ is(target.value, "",
+ kDescription + "Alt + Shift + Enter key should not cause inputting a line break");
+
+ reset();
+ synthesizeKey("KEY_Enter", {shiftKey: true, metaKey: true});
+ is(keydownFired, true,
+ kDescription + "keydown event should be fired when Meta + Shift + Enter key is pressed");
+ is(keypressFired, !kStrictKeyPressEvents,
+ kDescription + "keypress event shouldn't be fired when Meta + Shift + Enter key is pressed in strict keypress dispatching mode");
+ is(beforeinputFired, false,
+ kDescription + "beforeinput event shouldn't be fired when Meta + Shift + Enter key is pressed");
+ is(target.value, "",
+ kDescription + "Meta + Shift + Enter key should not cause inputting a line break");
+
+ target.removeEventListener("keydown", onEvent);
+ target.removeEventListener("keypress", onEvent);
+ target.removeEventListener("beforeinput", onEvent);
+ }
+}
+
+function runTests()
+{
+ testInitializingUntrustedEvent();
+ testSynthesizedKeyLocation();
+ testEnterKeyPressEvent();
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_dom_mouse_event.html b/dom/events/test/test_dom_mouse_event.html
new file mode 100644
index 0000000000..92352e4a25
--- /dev/null
+++ b/dom/events/test/test_dom_mouse_event.html
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for DOM MouseEvent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests, window);
+
+function testInitializingUntrustedEvent()
+{
+ const kTests = [
+ { createEventArg: "MouseEvent",
+ type: "mousedown", bubbles: true, cancelable: true, view: null, detail: 1,
+ screenX: 0, screenY: 0, clientX: 0, clientY: 0,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+ button: 6, relatedTarget: null },
+
+ { createEventArg: "mouseevent",
+ type: "mouseup", bubbles: false, cancelable: true, view: window, detail: 2,
+ screenX: 0, screenY: 0, clientX: 0, clientY: 400,
+ ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
+ button: 1, relatedTarget: document.getElementById("content") },
+
+ { createEventArg: "Mouseevent",
+ type: "click", bubbles: true, cancelable: false, view: null, detail: -5,
+ screenX: 0, screenY: 0, clientX: 300, clientY: 0,
+ ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
+ button: 2, relatedTarget: document.getElementById("test") },
+
+ { createEventArg: "mouseEvent",
+ type: "dblclick", bubbles: false, cancelable: false, view: window, detail: -1,
+ screenX: 0, screenY: 200, clientX: 0, clientY: 0,
+ ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
+ button: 12, relatedTarget: document.getElementById("content") },
+
+ { createEventArg: "MouseEvents",
+ type: "mouseenter", bubbles: true, cancelable: true, view: null, detail: 111000,
+ screenX: 100, screenY: 0, clientX: 0, clientY: 0,
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
+ button: 2, relatedTarget: document.getElementById("test") },
+
+ { createEventArg: "mouseevents",
+ type: "mouseleave", bubbles: false, cancelable: true, view: window, detail: 500,
+ screenX: 100, screenY: 500, clientX: 0, clientY: 0,
+ ctrlKey: true, altKey: true, shiftKey: false, metaKey: false,
+ button: 8, relatedTarget: document.getElementById("content") },
+
+ { createEventArg: "Mouseevents",
+ type: "mouseover", bubbles: true, cancelable: false, view: null, detail: 3,
+ screenX: 0, screenY: 0, clientX: 200, clientY: 300,
+ ctrlKey: false, altKey: true, shiftKey: false, metaKey: true,
+ button: 7, relatedTarget: document.getElementById("test") },
+
+ { createEventArg: "mouseEvents",
+ type: "mouseout", bubbles: false, cancelable: false, view: window, detail: 5,
+ screenX: -100, screenY: 300, clientX: 600, clientY: -500,
+ ctrlKey: true, altKey: false, shiftKey: true, metaKey: false,
+ button: 8, relatedTarget: document.getElementById("content") },
+
+ { createEventArg: "MouseEvent",
+ type: "mousemove", bubbles: false, cancelable: false, view: window, detail: 30,
+ screenX: 500, screenY: -100, clientX: -8888, clientY: -5000,
+ ctrlKey: true, altKey: false, shiftKey: true, metaKey: true,
+ button: 8, relatedTarget: document.getElementById("test") },
+
+ { createEventArg: "MouseEvent",
+ type: "foo", bubbles: false, cancelable: false, view: window, detail: 100,
+ screenX: 2000, screenY: 6000, clientX: 5000, clientY: 3000,
+ ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
+ button: 8, relatedTarget: document.getElementById("test") },
+ ];
+
+ const kOtherModifierName = [
+ "CapsLock", "NumLock", "ScrollLock", "Symbol", "SymbolLock", "Fn", "FnLock", "OS", "AltGraph"
+ ];
+
+ const kInvalidModifierName = [
+ "shift", "control", "alt", "meta", "capslock", "numlock", "scrolllock",
+ "symbollock", "fn", "os", "altgraph", "Invalid", "Shift Control",
+ "Win", "Scroll"
+ ];
+
+ for (var i = 0; i < kTests.length; i++) {
+ var description = "testInitializingUntrustedEvent, Index: " + i + ", ";
+ const kTest = kTests[i];
+ var e = document.createEvent(kTest.createEventArg);
+ e.initMouseEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view,
+ kTest.detail, kTest.screenX, kTest.screenY, kTest.clientX, kTest.clientY,
+ kTest.ctrlKey, kTest.altKey, kTest.shiftKey, kTest.metaKey,
+ kTest.button, kTest.relatedTarget);
+
+ for (var attr in kTest) {
+ if (attr == "createEventArg") {
+ continue;
+ }
+ is(e[attr], kTest[attr], description + attr + " returns wrong value");
+ }
+ is(e.isTrusted, false, description + "isTrusted returns wrong value");
+ is(e.buttons, 0, description + "buttons returns wrong value");
+ is(e.movementX, 0, description + "movementX returns wrong value");
+ is(e.movementY, 0, description + "movementY returns wrong value");
+
+ // getModifierState() tests
+ is(e.getModifierState("Shift"), kTest.shiftKey,
+ description + "getModifierState(\"Shift\") returns wrong value");
+ is(e.getModifierState("Control"), kTest.ctrlKey,
+ description + "getModifierState(\"Control\") returns wrong value");
+ is(e.getModifierState("Alt"), kTest.altKey,
+ description + "getModifierState(\"Alt\") returns wrong value");
+ is(e.getModifierState("Meta"), kTest.metaKey,
+ description + "getModifierState(\"Meta\") returns wrong value");
+
+ for (var j = 0; j < kOtherModifierName.length; j++) {
+ ok(!e.getModifierState(kOtherModifierName[j]),
+ description + "getModifierState(\"" + kOtherModifierName[j] + "\") returns wrong value");
+ }
+ for (var k = 0; k < kInvalidModifierName.length; k++) {
+ ok(!e.getModifierState(kInvalidModifierName[k]),
+ description + "getModifierState(\"" + kInvalidModifierName[k] + "\") returns wrong value");
+ }
+ }
+}
+
+function runTests()
+{
+ testInitializingUntrustedEvent();
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_dom_storage_event.html b/dom/events/test/test_dom_storage_event.html
new file mode 100644
index 0000000000..88cc288d41
--- /dev/null
+++ b/dom/events/test/test_dom_storage_event.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for DOM StorageEvent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+const kTests = [
+ { createEventArg: "StorageEvent",
+ type: "aaa", bubbles: true, cancelable: true,
+ key: null, oldValue: 'a', newValue: 'b', url: 'c', storageArea: null },
+
+ { createEventArg: "storageevent",
+ type: "bbb", bubbles: false, cancelable: true,
+ key: 'key', oldValue: null, newValue: 'b', url: 'c', storageArea: null },
+
+ { createEventArg: "Storageevent",
+ type: "ccc", bubbles: true, cancelable: false,
+ key: 'key', oldValue: 'a', newValue: null, url: 'c', storageArea: null },
+
+ { createEventArg: "storageEvent",
+ type: "ddd", bubbles: false, cancelable: false,
+ key: 'key', oldValue: 'a', newValue: 'b', url: null, storageArea: null },
+
+ { createEventArg: "StorageEvent",
+ type: "eee", bubbles: true, cancelable: true,
+ key: 'key', oldValue: 'a', newValue: 'b', url: 'c', storageArea: null },
+
+ { createEventArg: "storageevent",
+ type: "fff", bubbles: false, cancelable: true,
+ key: null, oldValue: null, newValue: null, url: null, storageArea: null },
+ ];
+
+for (var i = 0; i < kTests.length; i++) {
+ var description = "test, Index: " + i + ", ";
+ const kTest = kTests[i];
+ var e = document.createEvent(kTest.createEventArg);
+ e.initStorageEvent(kTest.type, kTest.bubbles, kTest.cancelable,
+ kTest.key, kTest.oldValue, kTest.newValue, kTest.url,
+ kTest.storageArea);
+
+ for (var attr in kTest) {
+ if (attr == 'createEventArg')
+ continue;
+
+ is(e[attr], kTest[attr], description + attr + " returns wrong value");
+ }
+ is(e.isTrusted, false, description + "isTrusted returns wrong value");
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_dom_wheel_event.html b/dom/events/test/test_dom_wheel_event.html
new file mode 100644
index 0000000000..ef6deda4b6
--- /dev/null
+++ b/dom/events/test/test_dom_wheel_event.html
@@ -0,0 +1,835 @@
+<!DOCTYPE HTML>
+<html style="font-size: 32px;">
+<head>
+ <title>Test for D3E WheelEvent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="scrollable" style="font-family: monospace; font-size: 16px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
+ <div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ </div>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTest, window);
+
+var gScrollableElement = document.getElementById("scrollable");
+var gScrolledElement = document.getElementById("scrolled");
+
+var gLineHeight = 0;
+var gHorizontalLine = 0;
+var gPageHeight = 0;
+var gPageWidth = 0;
+
+function sendWheelAndWait(aX, aY, aEvent)
+{
+ sendWheelAndPaint(gScrollableElement, aX, aY, aEvent, continueTest);
+}
+
+function* prepareScrollUnits()
+{
+ var result = -1;
+ function handler(aEvent)
+ {
+ result = aEvent.detail;
+ aEvent.preventDefault();
+ }
+ window.addEventListener("MozMousePixelScroll", handler, { capture: true, passive: false });
+
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gLineHeight = result;
+ ok(gLineHeight > 10 && gLineHeight < 25, "prepareScrollUnits: gLineHeight may be illegal value, got " + gLineHeight);
+
+ result = -1;
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gHorizontalLine = result;
+ ok(gHorizontalLine > 5 && gHorizontalLine < 16, "prepareScrollUnits: gHorizontalLine may be illegal value, got " + gHorizontalLine);
+
+ result = -1;
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gPageHeight = result;
+ // XXX Cannot we know the actual scroll port size?
+ ok(gPageHeight >= 150 && gPageHeight <= 200,
+ "prepareScrollUnits: gPageHeight is strange value, got " + gPageHeight);
+
+ result = -1;
+ yield sendWheelAndWait(10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gPageWidth = result;
+ ok(gPageWidth >= 150 && gPageWidth <= 200,
+ "prepareScrollUnits: gPageWidth is strange value, got " + gPageWidth);
+
+ window.removeEventListener("MozMousePixelScroll", handler, true);
+}
+
+function testMakingUntrustedEvent()
+{
+ const kCreateEventArgs = [
+ "WheelEvent", "wheelevent", "wheelEvent", "Wheelevent"
+ ];
+
+ for (var i = 0; i < kCreateEventArgs.length; i++) {
+ try {
+ // We never support WheelEvent construction with document.createEvent().
+ var event = document.createEvent(kCreateEventArgs[i]);
+ ok(false, "document.createEvent(" + kCreateEventArgs[i] + ") should throw an error");
+ } catch (e) {
+ ok(true, "document.createEvent(" + kCreateEventArgs[i] + ") threw an error");
+ }
+ }
+
+ var wheelEvent = new WheelEvent("wheel");
+ ok(wheelEvent instanceof WheelEvent,
+ "new WheelEvent() should create an instance of WheelEvent");
+ ok(typeof(wheelEvent.initWheelEvent) != "function",
+ "WheelEvent must not have initWheelEvent()");
+}
+
+// delta_multiplier prefs should cause changing delta values of trusted events only.
+// And also legacy events' detail value should be changed too.
+function* testDeltaMultiplierPrefs()
+{
+ const kModifierAlt = 0x01;
+ const kModifierControl = 0x02;
+ const kModifierMeta = 0x04;
+ const kModifierShift = 0x08;
+ const kModifierWin = 0x10;
+
+ const kTests = [
+ { name: "default",
+ expected: [ 0, kModifierShift | kModifierAlt, kModifierShift | kModifierControl,
+ kModifierShift | kModifierMeta, kModifierShift | kModifierWin,
+ kModifierControl | kModifierAlt, kModifierMeta | kModifierAlt ],
+ unexpected: [ kModifierAlt, kModifierControl, kModifierMeta, kModifierShift, kModifierWin ] },
+ { name: "with_alt",
+ expected: [ kModifierAlt ],
+ unexpected: [0, kModifierControl, kModifierMeta, kModifierShift, kModifierWin,
+ kModifierShift | kModifierAlt, kModifierControl | kModifierAlt,
+ kModifierMeta | kModifierAlt ] },
+ { name: "with_control",
+ expected: [ kModifierControl ],
+ unexpected: [0, kModifierAlt, kModifierMeta, kModifierShift, kModifierWin,
+ kModifierShift | kModifierControl, kModifierControl | kModifierAlt,
+ kModifierMeta | kModifierControl ] },
+ { name: "with_meta",
+ expected: [ kModifierMeta ],
+ unexpected: [0, kModifierAlt, kModifierControl, kModifierShift, kModifierWin,
+ kModifierShift | kModifierMeta, kModifierControl | kModifierMeta,
+ kModifierMeta | kModifierAlt ] },
+ { name: "with_shift",
+ expected: [ kModifierShift ],
+ unexpected: [0, kModifierAlt, kModifierControl, kModifierMeta, kModifierWin,
+ kModifierShift | kModifierAlt, kModifierControl | kModifierShift,
+ kModifierMeta | kModifierShift ] },
+ { name: "with_win",
+ expected: [ kModifierWin ],
+ unexpected: [0, kModifierAlt, kModifierControl, kModifierMeta, kModifierShift,
+ kModifierShift | kModifierWin ] },
+ ];
+
+ // Note that this test doesn't support complicated lineOrPageDelta values which are computed with
+ // accumulated delta values by the prefs. If you need to test the lineOrPageDelta accumulation,
+ // use test_continuous_dom_wheel_event.html.
+ const kEvents = [
+ { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: gHorizontalLine, deltaY: gLineHeight, deltaZ: gLineHeight, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -gHorizontalLine, deltaY: -gLineHeight, deltaZ: -gLineHeight, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ { deltaMode: WheelEvent.DOM_DELTA_LINE, skipDeltaModeCheck: true,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ ];
+
+ const kDeltaMultiplierPrefs = [
+ "delta_multiplier_x", "delta_multiplier_y", "delta_multiplier_z"
+ ];
+
+ const kPrefValues = [
+ 200, 50, 0, -50, -150
+ ];
+
+ var currentTest, currentModifiers, currentEvent, currentPref, currentMultiplier, testingExpected;
+ var expectedAsyncHandlerCalls;
+ var description;
+ var calledHandlers = { wheel: false,
+ DOMMouseScroll: { horizontal: false, vertical: false },
+ MozMousePixelScroll: { horizontal: false, vertical: false } };
+
+ function wheelEventHandler(aEvent) {
+ calledHandlers.wheel = true;
+
+ var expectedDeltaX = currentEvent.deltaX;
+ var expectedDeltaY = currentEvent.deltaY;
+ var expectedDeltaZ = currentEvent.deltaZ;
+
+ if (testingExpected) {
+ switch (currentPref.charAt(currentPref.length - 1)) {
+ case "x":
+ expectedDeltaX *= currentMultiplier;
+ break;
+ case "y":
+ expectedDeltaY *= currentMultiplier;
+ break;
+ case "z":
+ expectedDeltaZ *= currentMultiplier;
+ break;
+ }
+ }
+ if (currentEvent.skipDeltaModeCheck) {
+ let linesToPixel = SpecialPowers.getIntPref("dom.event.wheel-deltaMode-lines-to-pixel-scale");
+ expectedDeltaX *= linesToPixel;
+ expectedDeltaY *= linesToPixel;
+ expectedDeltaZ *= linesToPixel;
+ } else {
+ is(aEvent.deltaMode, currentEvent.deltaMode, description + "deltaMode (" + currentEvent.deltaMode + ") was invalid");
+ }
+ is(aEvent.deltaX, expectedDeltaX, description + "deltaX (" + currentEvent.deltaX + ") was invalid");
+ is(aEvent.deltaY, expectedDeltaY, description + "deltaY (" + currentEvent.deltaY + ") was invalid");
+ is(aEvent.deltaZ, expectedDeltaZ, description + "deltaZ (" + currentEvent.deltaZ + ") was invalid");
+ if (currentEvent.skipDeltaModeCheck) {
+ isnot(SpecialPowers.wrap(aEvent).deltaMode, aEvent.deltaMode, description + "deltaMode should be changed for content if unchecked");
+ }
+
+ if (expectedAsyncHandlerCalls > 0 && --expectedAsyncHandlerCalls == 0) {
+ setTimeout(continueTest, 0);
+ }
+ }
+
+ function legacyEventHandler(aEvent) {
+ var isHorizontal = (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS);
+ var isScrollEvent = (aEvent.type == "DOMMouseScroll");
+ if (isScrollEvent) {
+ if (isHorizontal) {
+ calledHandlers.DOMMouseScroll.horizontal = true;
+ } else {
+ calledHandlers.DOMMouseScroll.vertical = true;
+ }
+ } else {
+ if (isHorizontal) {
+ calledHandlers.MozMousePixelScroll.horizontal = true;
+ } else {
+ calledHandlers.MozMousePixelScroll.vertical = true;
+ }
+ }
+ var eventName = (isHorizontal ? "Horizontal " : "Vertical ") + aEvent.type + " ";
+ var expectedDetail;
+ if (isScrollEvent) {
+ expectedDetail = isHorizontal ? currentEvent.lineOrPageDeltaX : currentEvent.lineOrPageDeltaY;
+ if (currentEvent.deltaMode == WheelEvent.DOM_DELTA_PAGE && expectedDetail) {
+ expectedDetail = ((expectedDetail > 0) ? UIEvent.SCROLL_PAGE_DOWN : UIEvent.SCROLL_PAGE_UP);
+ }
+ } else {
+ expectedDetail = isHorizontal ? currentEvent.deltaX : currentEvent.deltaY;
+ if (expectedDetail) {
+ if (currentEvent.deltaMode == WheelEvent.DOM_DELTA_LINE) {
+ expectedDetail *= (isHorizontal ? gHorizontalLine : gLineHeight);
+ } else if (currentEvent.deltaMode == WheelEvent.DOM_DELTA_PAGE) {
+ if (expectedDetail > 0) {
+ expectedDetail = (isHorizontal ? gPageWidth : gPageHeight);
+ } else {
+ expectedDetail = (isHorizontal ? -gPageWidth : -gPageHeight);
+ }
+ }
+ }
+ }
+ if (testingExpected) {
+ if ((isHorizontal && currentPref.charAt(currentPref.length - 1) == "x") ||
+ (!isHorizontal && currentPref.charAt(currentPref.length - 1) == "y")) {
+ // If it's a page scroll event, the detail value is UIEvent.SCROLL_PAGE_DOWN or
+ // UIEvent.SCROLL_PAGE_UP. If the delta value sign is reverted, we need to
+ // revert the expected detail value too. Otherwise, don't touch it.
+ if (isScrollEvent && currentEvent.deltaMode == WheelEvent.DOM_DELTA_PAGE) {
+ if (currentMultiplier < 0) {
+ expectedDetail = ((expectedDetail == UIEvent.SCROLL_PAGE_UP) ? UIEvent.SCROLL_PAGE_DOWN : UIEvent.SCROLL_PAGE_UP);
+ }
+ } else {
+ expectedDetail *= currentMultiplier;
+ expectedDetail = expectedDetail < 0 ? Math.ceil(expectedDetail) : Math.floor(expectedDetail);
+ }
+ }
+ }
+ is(aEvent.detail, expectedDetail, description + eventName + "detail was invalid");
+
+ aEvent.preventDefault();
+
+ if (expectedAsyncHandlerCalls > 0 && --expectedAsyncHandlerCalls == 0) {
+ setTimeout(continueTest, 0);
+ }
+ }
+
+ window.addEventListener("wheel", wheelEventHandler, true);
+ window.addEventListener("DOMMouseScroll", legacyEventHandler, true);
+ window.addEventListener("MozMousePixelScroll", legacyEventHandler, true);
+
+ function* dispatchEvent(aIsExpected) {
+ for (var i = 0; i < kEvents.length; i++) {
+ currentEvent = kEvents[i];
+ currentEvent.shiftKey = (currentModifiers & kModifierShift) != 0;
+ currentEvent.ctrlKey = (currentModifiers & kModifierControl) != 0;
+ currentEvent.altKey = (currentModifiers & kModifierAlt) != 0;
+ currentEvent.metaKey = (currentModifiers & kModifierMeta) != 0;
+ currentEvent.osKey = (currentModifiers & kModifierWin) != 0;
+ var modifierList = "";
+ if (currentEvent.shiftKey) {
+ modifierList += "Shift ";
+ }
+ if (currentEvent.ctrlKey) {
+ modifierList += "Control ";
+ }
+ if (currentEvent.altKey) {
+ modifierList += "Alt ";
+ }
+ if (currentEvent.metaKey) {
+ modifierList += "Meta ";
+ }
+ if (currentEvent.osKey) {
+ modifierList += "Win ";
+ }
+
+ for (var j = 0; j < kPrefValues.length; j++) {
+ currentMultiplier = kPrefValues[j] / 100;
+ for (var k = 0; k < kDeltaMultiplierPrefs.length; k++) {
+ currentPref = "mousewheel." + currentTest.name + "." + kDeltaMultiplierPrefs[k];
+
+ yield SpecialPowers.pushPrefEnv({"set": [[currentPref, kPrefValues[j]]]}, continueTest);
+
+ gScrollableElement.scrollTop = gScrollableElement.scrollBottom = 1000;
+
+ // trusted event's delta valuses should be reverted by the pref.
+ testingExpected = aIsExpected;
+
+ var expectedProps = {
+ deltaX: currentEvent.deltaX * currentMultiplier,
+ deltaY: currentEvent.deltaY * currentMultiplier,
+ dletaZ: currentEvent.deltaZ * currentMultiplier,
+ lineOrPageDeltaX: currentEvent.lineOrPageDeltaX * currentMultiplier,
+ lineOrPageDeltaY: currentEvent.lineOrPageDeltaY * currentMultiplier,
+ };
+
+ var expectedWheel = expectedProps.deltaX != 0 || expectedProps.deltaY != 0 || expectedProps.deltaZ != 0;
+ var expectedDOMMouseX = expectedProps.lineOrPageDeltaX >= 1 || expectedProps.lineOrPageDeltaX <= -1;
+ var expectedDOMMouseY = expectedProps.lineOrPageDeltaY >= 1 || expectedProps.lineOrPageDeltaY <= -1;
+ var expectedMozMouseX = expectedProps.deltaX >= 1 || expectedProps.deltaX <= -1;
+ var expectedMozMouseY = expectedProps.deltaY >= 1 || expectedProps.deltaY <= -1;
+
+ expectedAsyncHandlerCalls = 0;
+ if (expectedWheel) ++expectedAsyncHandlerCalls;
+ if (expectedDOMMouseX) ++expectedAsyncHandlerCalls;
+ if (expectedDOMMouseY) ++expectedAsyncHandlerCalls;
+ if (expectedMozMouseX) ++expectedAsyncHandlerCalls;
+ if (expectedMozMouseY) ++expectedAsyncHandlerCalls;
+
+ description = "testDeltaMultiplierPrefs, pref: " + currentPref + "=" + kPrefValues[j] +
+ ", deltaMode: " + currentEvent.deltaMode + ", modifiers: \"" + modifierList + "\", (trusted event): ";
+ yield synthesizeWheel(gScrollableElement, 10, 10, currentEvent);
+
+ is(calledHandlers.wheel,
+ expectedWheel,
+ description + "wheel event was (not) fired");
+ is(calledHandlers.DOMMouseScroll.horizontal,
+ expectedDOMMouseX,
+ description + "Horizontal DOMMouseScroll event was (not) fired");
+ is(calledHandlers.DOMMouseScroll.vertical,
+ expectedDOMMouseY,
+ description + "Vertical DOMMouseScroll event was (not) fired");
+ is(calledHandlers.MozMousePixelScroll.horizontal,
+ expectedMozMouseX,
+ description + "Horizontal MozMousePixelScroll event was (not) fired");
+ is(calledHandlers.MozMousePixelScroll.vertical,
+ expectedMozMouseY,
+ description + "Vertical MozMousePixelScroll event was (not) fired");
+
+ calledHandlers = { wheel: false,
+ DOMMouseScroll: { horizontal: false, vertical: false },
+ MozMousePixelScroll: { horizontal: false, vertical: false } };
+
+ // untrusted event's delta values shouldn't be reverted by the pref.
+ testingExpected = false;
+ var props = {
+ bubbles: true,
+ cancelable: true,
+ shiftKey: currentEvent.shiftKey,
+ ctrlKey: currentEvent.ctrlKey,
+ altKey: currentEvent.altKey,
+ metaKey: currentEvent.metaKey,
+ deltaX: currentEvent.deltaX,
+ deltaY: currentEvent.deltaY,
+ deltaZ: currentEvent.deltaZ,
+ deltaMode: currentEvent.deltaMode,
+ };
+ var untrustedEvent = new WheelEvent("wheel", props);
+
+ description = "testDeltaMultiplierPrefs, pref: " + currentPref + "=" + kPrefValues[j] +
+ ", deltaMode: " + currentEvent.deltaMode + ", modifiers: \"" + modifierList + "\", (untrusted event): ";
+ gScrollableElement.dispatchEvent(untrustedEvent);
+
+ ok(calledHandlers.wheel, description + "wheel event was not fired for untrusted event");
+ ok(!calledHandlers.DOMMouseScroll.horizontal,
+ description + "Horizontal DOMMouseScroll event was fired for untrusted event");
+ ok(!calledHandlers.DOMMouseScroll.vertical,
+ description + "Vertical DOMMouseScroll event was fired for untrusted event");
+ ok(!calledHandlers.MozMousePixelScroll.horizontal,
+ description + "Horizontal MozMousePixelScroll event was fired for untrusted event");
+ ok(!calledHandlers.MozMousePixelScroll.vertical,
+ description + "Vertical MozMousePixelScroll event was fired for untrusted event");
+
+ yield SpecialPowers.pushPrefEnv({"set": [[currentPref, 100]]}, continueTest);
+
+ calledHandlers = { wheel: false,
+ DOMMouseScroll: { horizontal: false, vertical: false },
+ MozMousePixelScroll: { horizontal: false, vertical: false } };
+
+ }
+ // We should skip other value tests if testing with modifier key.
+ // If we didn't do so, it would test too many times, but we don't need to do so.
+ if (kTests.name != "default") {
+ break;
+ }
+ }
+ }
+ }
+
+ for (var i = 0; i < kTests.length; i++) {
+ currentTest = kTests[i];
+ for (var j = 0; j < currentTest.expected.length; j++) {
+ currentModifiers = currentTest.expected[j];
+ yield* dispatchEvent(true);
+ }
+ for (var k = 0; k < currentTest.unexpected.length; k++) {
+ currentModifiers = currentTest.unexpected[k];
+ yield* dispatchEvent(false);
+ }
+ }
+
+ window.removeEventListener("wheel", wheelEventHandler, true);
+ window.removeEventListener("DOMMouseScroll", legacyEventHandler, true);
+ window.removeEventListener("MozMousePixelScroll", legacyEventHandler, true);
+}
+
+// Untrusted wheel events shouldn't cause legacy mouse scroll events.
+function testDispatchingUntrustEvent()
+{
+ var descriptionBase = "testDispatchingUntrustEvent, ";
+ var description, wheelEventFired;
+ function wheelEventHandler(aEvent)
+ {
+ wheelEventFired = true;
+ }
+
+ function legacyEventHandler(aEvent)
+ {
+ ok(false, aEvent.type + " must not be fired");
+ }
+
+ window.addEventListener("wheel", wheelEventHandler, true);
+ window.addEventListener("DOMMouseScroll", legacyEventHandler, true);
+ window.addEventListener("MozMousePixelScroll", legacyEventHandler, true);
+
+ description = descriptionBase + "dispatching a pixel wheel event: ";
+ wheelEventFired = false;
+ var untrustedPixelEvent = new WheelEvent("wheel", {
+ bubbles: true, cancelable: true,
+ deltaX: 24.0, deltaY: 24.0,
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ });
+ gScrolledElement.dispatchEvent(untrustedPixelEvent);
+ ok(wheelEventFired, description + "wheel event wasn't fired");
+
+ description = descriptionBase + "dispatching a line wheel event: ";
+ wheelEventFired = false;
+ var untrustedLineEvent = new WheelEvent("wheel", {
+ bubbles: true, cancelable: true,
+ deltaX: 3.0, deltaY: 3.0,
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ });
+ gScrolledElement.dispatchEvent(untrustedLineEvent);
+ ok(wheelEventFired, description + "wheel event wasn't fired");
+
+ description = descriptionBase + "dispatching a page wheel event: ";
+ wheelEventFired = false;
+ var untrustedPageEvent = new WheelEvent("wheel", {
+ bubbles: true, cancelable: true,
+ deltaX: 1.0, deltaY: 1.0,
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ });
+ gScrolledElement.dispatchEvent(untrustedPageEvent);
+ ok(wheelEventFired, description + "wheel event wasn't fired");
+
+ window.removeEventListener("wheel", wheelEventHandler, true);
+ window.removeEventListener("DOMMouseScroll", legacyEventHandler, true);
+ window.removeEventListener("MozMousePixelScroll", legacyEventHandler, true);
+}
+
+function* testEventOrder()
+{
+ const kWheelEvent = 0x0001;
+ const kDOMMouseScrollEvent = 0x0002;
+ const kMozMousePixelScrollEvent = 0x0004;
+ const kVerticalScrollEvent = 0x0010;
+ const kHorizontalScrollEvent = 0x0020;
+ const kInSystemGroup = 0x0100;
+ const kDefaultPrevented = 0x1000;
+
+ var currentTest;
+
+ const kTests = [
+ {
+ description: "Testing the order of the events without preventDefault()",
+ expectedEvents: [ kWheelEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kWheelEvent | kInSystemGroup],
+ resultEvents: [],
+ doPreventDefaultAt: 0,
+ },
+ {
+ description: "Testing the order of the events, calling preventDefault() at default group wheel event",
+ expectedEvents: [ kWheelEvent,
+ kWheelEvent | kInSystemGroup | kDefaultPrevented],
+ resultEvents: [],
+ doPreventDefaultAt: kWheelEvent,
+ },
+ {
+ description: "Testing the order of the events, calling preventDefault() at default group DOMMouseScroll event",
+ expectedEvents: [ kWheelEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent | kDefaultPrevented,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kWheelEvent | kInSystemGroup | kDefaultPrevented],
+ resultEvents: [],
+ doPreventDefaultAt: kDOMMouseScrollEvent | kVerticalScrollEvent,
+ },
+ {
+ description: "Testing the order of the events, calling preventDefault() at default group MozMousePixelScroll event",
+ expectedEvents: [ kWheelEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kWheelEvent | kInSystemGroup | kDefaultPrevented],
+ resultEvents: [],
+ doPreventDefaultAt: kMozMousePixelScrollEvent | kVerticalScrollEvent,
+ },
+ {
+ description: "Testing the order of the events, calling preventDefault() at system group DOMMouseScroll event",
+ expectedEvents: [ kWheelEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent | kDefaultPrevented,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup | kDefaultPrevented,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kWheelEvent | kInSystemGroup | kDefaultPrevented],
+ resultEvents: [],
+ doPreventDefaultAt: kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ },
+ {
+ description: "Testing the order of the events, calling preventDefault() at system group MozMousePixelScroll event",
+ expectedEvents: [ kWheelEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent,
+ kDOMMouseScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent,
+ kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent,
+ kDOMMouseScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent,
+ kMozMousePixelScrollEvent | kHorizontalScrollEvent | kInSystemGroup,
+ kWheelEvent | kInSystemGroup | kDefaultPrevented],
+ resultEvents: [],
+ doPreventDefaultAt: kMozMousePixelScrollEvent | kVerticalScrollEvent | kInSystemGroup,
+ },
+ ];
+
+ function getEventDescription(aEvent)
+ {
+ var result = "";
+ if (aEvent & kWheelEvent) {
+ result = "wheel"
+ } else {
+ if (aEvent & kDOMMouseScrollEvent) {
+ result = "DOMMouseScroll";
+ } else if (aEvent & kMozMousePixelScrollEvent) {
+ result = "MozMousePixelScroll";
+ }
+ if (aEvent & kVerticalScrollEvent) {
+ result += ", vertical";
+ } else {
+ result += ", horizontal";
+ }
+ }
+ if (aEvent & kInSystemGroup) {
+ result += ", system group";
+ }
+ if (aEvent & kDefaultPrevented) {
+ result += ", defaultPrevented";
+ }
+ return result;
+ }
+
+ function pushEvent(aEvent, aIsSystemGroup)
+ {
+ var event = 0;
+ if (aEvent.type == "wheel") {
+ event = kWheelEvent;
+ } else {
+ if (aEvent.type == "DOMMouseScroll") {
+ event = kDOMMouseScrollEvent;
+ } else if (aEvent.type == "MozMousePixelScroll") {
+ event = kMozMousePixelScrollEvent;
+ }
+ if (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS) {
+ event |= kHorizontalScrollEvent;
+ } else {
+ event |= kVerticalScrollEvent;
+ }
+ }
+ if (aIsSystemGroup) {
+ event |= kInSystemGroup;
+ }
+ if (aEvent.defaultPrevented) {
+ event |= kDefaultPrevented;
+ }
+ currentTest.resultEvents.push(event);
+
+ if (event == currentTest.doPreventDefaultAt) {
+ aEvent.preventDefault();
+ }
+
+ if (currentTest.resultEvents.length == currentTest.expectedEvents.length) {
+ setTimeout(continueTest, 0);
+ }
+ }
+
+ function handler(aEvent)
+ {
+ pushEvent(aEvent, false);
+ }
+
+ function systemHandler(aEvent)
+ {
+ pushEvent(aEvent, true);
+ }
+
+ window.addEventListener("wheel", handler, { capture: true, passive: false });
+ window.addEventListener("DOMMouseScroll", handler, { capture: true, passive: false });
+ window.addEventListener("MozMousePixelScroll", handler, { capture: true, passive: false });
+
+ SpecialPowers.addSystemEventListener(window, "wheel", systemHandler, true);
+ SpecialPowers.addSystemEventListener(window, "DOMMouseScroll", systemHandler, true);
+ SpecialPowers.addSystemEventListener(window, "MozMousePixelScroll", systemHandler, true);
+
+ for (var i = 0; i < kTests.length; i++) {
+ currentTest = kTests[i];
+ yield synthesizeWheel(gScrollableElement, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE, deltaX: 1.0, deltaY: 1.0 });
+
+ for (var j = 0; j < currentTest.expectedEvents.length; j++) {
+ if (currentTest.resultEvents.length == j) {
+ ok(false, currentTest.description + ": " +
+ getEventDescription(currentTest.expectedEvents[j]) + " wasn't fired");
+ break;
+ }
+ is(getEventDescription(currentTest.resultEvents[j]),
+ getEventDescription(currentTest.expectedEvents[j]),
+ currentTest.description + ": " + (j + 1) + "th event is mismatched");
+ }
+ if (currentTest.expectedEvents.length < currentTest.resultEvents.length) {
+ ok(false, currentTest.description + ": " +
+ getEventDescription(currentTest.resultEvents[currentTest.expectedEvents.length]) +
+ " was fired unexpectedly");
+ }
+ }
+
+ window.removeEventListener("wheel", handler, true);
+ window.removeEventListener("DOMMouseScroll", handler, true);
+ window.removeEventListener("MozMousePixelScroll", handler, true);
+
+ SpecialPowers.removeSystemEventListener(window, "wheel", systemHandler, true);
+ SpecialPowers.removeSystemEventListener(window, "DOMMouseScroll", systemHandler, true);
+ SpecialPowers.removeSystemEventListener(window, "MozMousePixelScroll", systemHandler, true);
+}
+
+var gOnWheelAttrHandled = new Array;
+var gOnWheelAttrCount = 0;
+
+function* testOnWheelAttr()
+{
+ function onWheelHandledString(attr) {
+ return `gOnWheelAttrHandled['${attr}'] = true;
+ ++gOnWheelAttrCount;
+ if (gOnWheelAttrCount == 3) {
+ setTimeout(continueTest, 0);
+ };`;
+ }
+
+ document.documentElement.setAttribute("onwheel", onWheelHandledString("html"));
+ document.body.setAttribute("onwheel", onWheelHandledString("body"));
+ gScrollableElement.setAttribute("onwheel", onWheelHandledString("div"));
+ var target = document.getElementById("onwheel");
+ yield synthesizeWheel(gScrollableElement, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 2.0 });
+ ok(gOnWheelAttrHandled.html, "html element's onwheel attribute isn't performed");
+ ok(gOnWheelAttrHandled.body, "body element's onwheel attribute isn't performed");
+ ok(gOnWheelAttrHandled.div, "div element's onwheel attribute isn't performed");
+}
+
+var gOnWheelPropHandled = new Array;
+var gOnWheelPropCount = 0;
+
+function* testOnWheelProperty()
+{
+ const handleOnWheelProp = prop => e => {
+ gOnWheelPropHandled[prop] = true;
+ ++gOnWheelPropCount;
+ if (gOnWheelPropCount == 5) {
+ setTimeout(continueTest, 0);
+ }
+ }
+
+ window.onwheel = handleOnWheelProp('window');
+ document.onwheel = handleOnWheelProp('document');
+ document.documentElement.onwheel = handleOnWheelProp('html');
+ document.body.onwheel = handleOnWheelProp('body');
+ gScrollableElement.onwheel = handleOnWheelProp('div');
+
+ var target = document.getElementById("onwheel");
+ yield synthesizeWheel(gScrollableElement, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 2.0 });
+
+ ok(gOnWheelPropHandled.window, "window's onwheel property isn't performed");
+ ok(gOnWheelPropHandled.document, "document's onwheel property isn't performed");
+ ok(gOnWheelPropHandled.html, "html element's onwheel property isn't performed");
+ ok(gOnWheelPropHandled.body, "body element's onwheel property isn't performed");
+ ok(gOnWheelPropHandled.div, "div element's onwheel property isn't performed");
+}
+
+function* testBody()
+{
+ yield* prepareScrollUnits();
+ testMakingUntrustedEvent();
+ yield* testDeltaMultiplierPrefs();
+ testDispatchingUntrustEvent();
+ yield* testEventOrder();
+ yield* testOnWheelAttr();
+ yield* testOnWheelProperty();
+}
+
+var gTestContinuation = null;
+
+function continueTest()
+{
+ if (!gTestContinuation) {
+ gTestContinuation = testBody();
+ }
+ var ret = gTestContinuation.next();
+ if (ret.done) {
+ SimpleTest.finish();
+ }
+}
+
+function runTest()
+{
+ SpecialPowers.pushPrefEnv({"set": [
+ // FIXME(emilio): This test is broken in HiDPI, unclear if
+ // MozMousePixelScroll is not properly converting to CSS pixels, or
+ // whether sendWheelAndWait expectes device rather than CSS pixels, or
+ // something else.
+ ["layout.css.devPixelsPerPx", 1.0],
+
+ ["dom.event.wheel-deltaMode-lines.disabled", true],
+
+ ["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100],
+ ["mousewheel.default.delta_multiplier_z", 100],
+ ["mousewheel.with_alt.delta_multiplier_x", 100],
+ ["mousewheel.with_alt.delta_multiplier_y", 100],
+ ["mousewheel.with_alt.delta_multiplier_z", 100],
+ ["mousewheel.with_control.delta_multiplier_x", 100],
+ ["mousewheel.with_control.delta_multiplier_y", 100],
+ ["mousewheel.with_control.delta_multiplier_z", 100],
+ ["mousewheel.with_meta.delta_multiplier_x", 100],
+ ["mousewheel.with_meta.delta_multiplier_y", 100],
+ ["mousewheel.with_meta.delta_multiplier_z", 100],
+ ["mousewheel.with_shift.delta_multiplier_x", 100],
+ ["mousewheel.with_shift.delta_multiplier_y", 100],
+ ["mousewheel.with_shift.delta_multiplier_z", 100],
+ ["mousewheel.with_win.delta_multiplier_x", 100],
+ ["mousewheel.with_win.delta_multiplier_y", 100],
+ ["mousewheel.with_win.delta_multiplier_z", 100],
+ // TODO: Need to add passive to SpecialPowers.addSystemEventListener
+ // somehow.
+ ["dom.event.default_to_passive_wheel_listeners", false],
+ ]}, continueTest);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_draggableprop.html b/dom/events/test/test_draggableprop.html
new file mode 100644
index 0000000000..7a5b5914db
--- /dev/null
+++ b/dom/events/test/test_draggableprop.html
@@ -0,0 +1,89 @@
+<html>
+<head>
+ <title>Tests for the draggable property on HTML elements</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+ <script type="application/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<span id="elem1">One</span>
+<span id="elem2" draggable="true">Two</span>
+<span id="elem3" draggable="">Three</span>
+<span id="elem4" draggable="false">Four</span>
+<span id="elem5" draggable="other">Five</span>
+
+<img id="img1" src="../happy.png">
+<img id="img2" src="../happy.png" draggable="true">
+<img id="img3" src="../happy.png" draggable="">
+<img id="img4" src="../happy.png" draggable="false">
+<img id="img5" src="../happy.png" draggable="other">
+
+<a id="a1">One</a>
+<a id="a2" draggable="true">Two</a>
+<a id="a3" draggable="">Three</a>
+<a id="a4" draggable="false">Four</a>
+<a id="a5" draggable="other">Five</a>
+
+<a id="ahref1" href="http://www.mozilla.org">One</a>
+<a id="ahref2" href="http://www.mozilla.org" draggable="true">Two</a>
+<a id="ahref3" href="http://www.mozilla.org" draggable="">Three</a>
+<a id="ahref4" href="http://www.mozilla.org" draggable="false">Four</a>
+<a id="ahref5" href="http://www.mozilla.org" draggable="other">Five</a>
+
+<script>
+function check()
+{
+ try {
+ checkElements(1, false, true, false, true);
+ checkElements(2, true, true, true, true);
+ checkElements(3, false, true, false, true);
+ checkElements(4, false, false, false, false);
+ checkElements(5, false, true, false, true);
+ }
+ catch (ex) {
+ is("script error", ex, "fail");
+ }
+}
+
+function checkElements(idx, estate, istate, astate, ahrefstate)
+{
+ checkElement("elem" + idx, estate, false);
+ checkElement("img" + idx, istate, true);
+ checkElement("a" + idx, astate, false);
+ checkElement("ahref" + idx, ahrefstate, true);
+}
+
+function checkElement(elemid, state, statedef)
+{
+ var elem = document.getElementById(elemid);
+
+ is(elem.draggable, state, elemid + "-initial");
+ elem.draggable = true;
+ is(elem.draggable, true, elemid + "-true");
+ elem.draggable = false;
+ is(elem.draggable, false, elemid + "-false");
+
+ elem.setAttribute("draggable", "true");
+ is(elem.draggable, true, elemid + "-attr-true");
+ elem.setAttribute("draggable", "false");
+ is(elem.draggable, false, elemid + "-attr-false");
+ elem.setAttribute("draggable", "other");
+ is(elem.draggable, statedef, elemid + "-attr-other");
+ elem.setAttribute("draggable", "");
+ is(elem.draggable, statedef, elemid + "-attr-empty");
+ elem.removeAttribute("draggable");
+ is(elem.draggable, statedef, elemid + "-attr-removed");
+}
+
+check();
+
+</script>
+
+</body>
+</html>
+
+
diff --git a/dom/events/test/test_dragstart.html b/dom/events/test/test_dragstart.html
new file mode 100644
index 0000000000..9318e54566
--- /dev/null
+++ b/dom/events/test/test_dragstart.html
@@ -0,0 +1,631 @@
+<html>
+<head>
+ <title>Tests for the dragstart event</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+
+<!--
+ This test checks the dragstart event and the DataTransfer object
+ -->
+
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+var gDragInfo;
+var gDataTransfer = null;
+var gExtraDragTests = 0;
+
+function runTests()
+{
+ // first, create a selection and try dragging it
+ var draggable = $("draggable");
+ window.getSelection().selectAllChildren(draggable);
+ synthesizeMouse(draggable, 6, 6, { type: "mousedown" });
+ synthesizeMouse(draggable, 14, 14, { type: "mousemove" });
+ // drags are asynchronous on Linux, so this extra event is needed to make
+ // sure the drag gets processed
+ synthesizeMouse(draggable, 15, 15, { type: "mousemove" });
+}
+
+function afterDragTests()
+{
+ // the dragstart should have occurred due to moving the mouse. gDataTransfer
+ // caches the dataTransfer that was used, however it should now be empty and
+ // be read only.
+ ok(gDataTransfer instanceof DataTransfer, "DataTransfer after dragstart event");
+ checkTypes(gDataTransfer, [], 0, "after dragstart event");
+
+ expectError(() => gDataTransfer.setData("text/plain", "Some Text"),
+ "NoModificationAllowedError", "setData when read only");
+ expectError(() => gDataTransfer.clearData("text/plain"),
+ "NoModificationAllowedError", "clearData when read only");
+ expectError(() => gDataTransfer.addElement(draggable),
+ "NoModificationAllowedError", "addElement when read only");
+
+ var evt = document.createEvent("dragevent");
+ ok(evt instanceof DragEvent, "synthetic dragevent class")
+ ok(evt instanceof MouseEvent, "synthetic event inherits from MouseEvent")
+ evt.initDragEvent("dragstart", true, true, window, 1, 40, 35, 20, 15,
+ false, true, false, false, 0, null, null);
+ $("synthetic").dispatchEvent(evt);
+
+ var evt = document.createEvent("dragevent");
+ ok(evt instanceof DragEvent, "synthetic dragevent class")
+ evt.initDragEvent("dragover", true, true, window, 0, 40, 35, 20, 15,
+ true, false, true, true, 2, document.documentElement, null);
+ $("synthetic2").dispatchEvent(evt);
+
+ // next, dragging links and images
+ sendMouseEventsForDrag("link");
+ sendMouseEventsForDrag("image");
+
+// disable testing input dragging for now, as it doesn't seem to be testable
+// draggable = $("input");
+// draggable.setSelectionRange(0, 4);
+// synthesizeMouse(draggable, 8, 8, { type: "mousedown" });
+// synthesizeMouse(draggable, 15, 15, { type: "mousemove" });
+// sendMouseEventsForDrag("input");
+
+ // draggable element inside a shadow root
+ sendMouseEventsForShadowRootDrag();
+
+ // next, check if the draggable attribute can be used to adjust the drag target
+ gDragInfo = { target: $("dragtrue"), testid: "draggable true node" };
+ sendMouseEventsForDrag("dragtrue");
+ gDragInfo = { target: $("dragtrue"), testid: "draggable true child" };
+ sendMouseEventsForDrag("spantrue");
+ gDragInfo = { target: $("dragfalse").firstChild, testid: "draggable false node" };
+ sendMouseEventsForDrag("dragfalse");
+ gDragInfo = { target: $("spanfalse").firstChild, testid: "draggable false child" };
+ sendMouseEventsForDrag("spanfalse");
+
+ synthesizeMouse(draggable, 12, 12, { type: "mouseup" });
+ if (gExtraDragTests == 5)
+ SimpleTest.finish();
+}
+
+function sendMouseEventsForDrag(nodeid)
+{
+ var draggable = $(nodeid);
+ synthesizeMouse(draggable, 3, 3, { type: "mousedown" });
+ synthesizeMouse(draggable, 10, 10, { type: "mousemove" });
+ synthesizeMouse(draggable, 12, 12, { type: "mousemove" });
+}
+function sendMouseEventsForShadowRootDrag()
+{
+ var draggable = $("shadow_host_containing_draggable").shadowRoot.firstElementChild;
+ synthesizeMouse(draggable, 3, 3, { type: "mousedown" });
+ synthesizeMouse(draggable, 10, 10, { type: "mousemove" });
+ synthesizeMouse(draggable, 12, 12, { type: "mousemove" });
+}
+
+function doDragStartSelection(event)
+{
+ is(event.type, "dragstart", "dragstart event type");
+ is(event.target, $("draggable").firstChild, "dragstart event target");
+ is(event.bubbles, true, "dragstart event bubbles");
+ is(event.cancelable, true, "dragstart event cancelable");
+
+ is(event.clientX, 14, "dragstart clientX");
+ is(event.clientY, 14, "dragstart clientY");
+ ok(event.screenX > 0, "dragstart screenX");
+ ok(event.screenY > 0, "dragstart screenY");
+ is(event.layerX, 14, "dragstart layerX");
+ is(event.layerY, 14, "dragstart layerY");
+ is(event.pageX, 14, "dragstart pageX");
+ is(event.pageY, 14, "dragstart pageY");
+
+ var dt = event.dataTransfer;
+ ok(dt instanceof DataTransfer, "dataTransfer is DataTransfer");
+ gDataTransfer = dt;
+
+ var types = dt.types;
+ ok(Array.isArray(types), "initial types is an Array");
+ checkTypes(dt, ["text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial selection");
+
+ is(dt.getData("text/plain"), "This is a draggable bit of text.", "initial selection text/plain");
+ is(dt.getData("text/html"), "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>",
+ "initial selection text/html");
+
+ // text/unicode and Text are available for compatibility. They retrieve the
+ // text/plain data
+ is(dt.getData("text/unicode"), "This is a draggable bit of text.", "initial selection text/unicode");
+ is(dt.getData("Text"), "This is a draggable bit of text.", "initial selection Text");
+ is(dt.getData("TEXT"), "This is a draggable bit of text.", "initial selection TEXT");
+ is(dt.getData("text/UNICODE"), "This is a draggable bit of text.", "initial selection text/UNICODE");
+
+ is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial selection item count");
+
+ dt.clearData("text/plain");
+ dt.clearData("text/html");
+ dt.clearData("text/_moz_htmlinfo");
+ dt.clearData("text/_moz_htmlcontext");
+
+ test_DataTransfer(dt);
+ setTimeout(afterDragTests, 0);
+}
+
+function test_DataTransfer(dt)
+{
+ is(SpecialPowers.wrap(dt).mozItemCount, 0, "empty itemCount");
+
+ var types = dt.types;
+ ok(Array.isArray(types), "empty types is an Array");
+ // The above test fails if we have SpecialPowers.wrap(dt).types instead of dt.types
+ // because chrome consumers get the 'ReturnValueNeedsContainsHack'.
+ // So wrap with special powers after the test
+ dt = SpecialPowers.wrap(dt);
+ checkTypes(dt, [], 0, "empty");
+ is(dt.getData("text/plain"), "", "empty data is empty");
+
+ // calling setDataAt requires an index that is 0 <= index <= dt.itemCount
+ expectError(() => dt.mozSetDataAt("text/plain", "Some Text", 1),
+ "IndexSizeError", "setDataAt index too high");
+
+ is(dt.mozUserCancelled, false, "userCancelled");
+
+ // because an exception occurred, the data should not have been added
+ is(dt.mozItemCount, 0, "empty setDataAt index too high itemCount");
+ dt.getData("text/plain", "", "empty setDataAt index too high getData");
+
+ // if the type is '', do nothing, or return ''
+ dt.setData("", "Invalid Type");
+ is(dt.types.length, 0, "invalid type setData");
+ is(dt.getData(""), "", "invalid type getData"),
+ dt.mozSetDataAt("", "Invalid Type", 0);
+ is(dt.types.length, 0, "invalid type setDataAt");
+ is(dt.mozGetDataAt("", 0), null, "invalid type getDataAt"),
+
+ // similar with clearDataAt and getDataAt
+ expectError(() => dt.mozGetDataAt("text/plain", 1),
+ "IndexSizeError", "getDataAt index too high");
+ expectError(() => dt.mozClearDataAt("text/plain", 1),
+ "IndexSizeError", "clearDataAt index too high");
+
+ dt.setData("text/plain", "Sample Text");
+ is(dt.mozItemCount, 1, "added plaintext itemCount");
+ checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext");
+
+ // after all those exceptions, the data should still be the same
+ checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext after exception");
+
+ // modifying the data associated with the format should give it the new value
+ dt.setData("text/plain", "Modified Text");
+ is(dt.mozItemCount, 1, "modified plaintext itemCount");
+ checkOneDataItem(dt, ["text/plain"], ["Modified Text"], 0, "modified plaintext");
+
+ dt.setData("text/html", "<strong>Modified Text</strong>");
+ is(dt.mozItemCount, 1, "modified html itemCount");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["Modified Text", "<strong>Modified Text</strong>"],
+ 0, "modified html");
+
+ // modifying data for a type that already exists should adjust it in place,
+ // not reinsert it at the beginning
+ dt.setData("text/plain", "New Text");
+ is(dt.mozItemCount, 1, "modified text again itemCount");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["New Text", "<strong>Modified Text</strong>"],
+ 0, "modified text again");
+
+ var draggable = $("draggable");
+ dt.setData("application/-moz-node", draggable);
+ checkOneDataItem(dt, ["text/plain", "text/html", "application/-moz-node"],
+ ["New Text", "<strong>Modified Text</strong>", draggable.toString()],
+ 0, "added node");
+
+ dt.clearData(""); // null means clear all
+ is(dt.mozItemCount, 0, "itemCount after clearData empty string");
+ checkTypes(dt, [], 0, "empty after clearData empty string");
+
+ dt.setData("text/plain", 22);
+ dt.setData("text/html", 5.6);
+ dt.setData("text/xml", 5.6);
+ checkTypes(dt, ["text/plain", "text/html", "text/xml"], ["22", "5.6", ""], 0, "add numeric and empty data");
+
+ dt.clearData(); // no argument means clear all
+ is(dt.mozItemCount, 0, "itemCount after clearData no argument");
+ checkTypes(dt, [], 0, "empty after clearData no argument");
+
+ // check 'Text' type which should convert into text/plain
+ dt.setData("Text", "Sample Text");
+ checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "set Text");
+ is(dt.getData("Text"), "Sample Text", "getData Text");
+ is(dt.mozGetDataAt("Text", 0), "Sample Text", "getDataAt Text");
+ dt.setData("text/plain", "More Text");
+ checkOneDataItem(dt, ["text/plain"], ["More Text"], 0, "set text/plain after set Text");
+
+ dt.mozClearDataAt("", 0); // null means clear all
+ is(dt.mozItemCount, 0, "itemCount after clearDataAt empty string");
+ checkTypes(dt, [], 0, "empty after clearDataAt empty string");
+
+ // check text/uri-list type
+ dt.setData("text/uri-list", "http://www.mozilla.org");
+ checkURL(dt, "http://www.mozilla.org", "http://www.mozilla.org", 0, "set text/uri-list");
+
+ // check URL type which should add text/uri-list data
+ dt.setData("URL", "ftp://ftp.example.com");
+ checkURL(dt, "ftp://ftp.example.com", "ftp://ftp.example.com", 0, "set URL");
+ checkTypes(dt, ["text/uri-list"], ["ftp://ftp.example.com"], "url types");
+
+ // clearing text/uri-list data
+ dt.clearData("text/uri-list");
+ is(dt.mozItemCount, 0, "itemCount after clear url-list");
+ is(dt.getData("text/uri-list"), "", "text/uri-list after clear url-list");
+ is(dt.getData("URL"), "", "URL after clear url-list");
+
+ // check text/uri-list parsing
+ dt.setData("text/uri-list", "#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com");
+ checkURL(dt, "http://www.xulplanet.com",
+ "#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com",
+ 0, "uri-list 3 lines");
+
+ dt.setData("text/uri-list", "#http://www.mozilla.org");
+ is(dt.getData("URL"), "", "uri-list commented");
+ dt.setData("text/uri-list", "#http://www.mozilla.org\n");
+ is(dt.getData("URL"), "", "uri-list commented with newline");
+
+ // check that clearing the URL type also clears the text/uri-list type
+ dt.clearData("URL");
+ is(dt.getData("text/uri-list"), "", "clear URL");
+
+ dt.setData("text/uri-list", "#http://www.mozilla.org\n\n\n\n\n");
+ is(dt.getData("URL"), "", "uri-list with blank lines");
+ dt.setData("text/uri-list", "");
+ is(dt.getData("URL"), "", "empty uri-list");
+ dt.setData("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n");
+ is(dt.getData("URL"), "http://www.xulplanet.com", "uri-list mix");
+ dt.setData("text/uri-list", "\nhttp://www.mozilla.org");
+ is(dt.getData("URL"), "", "empty line to start uri-list");
+ dt.setData("text/uri-list", " http://www.mozilla.org#anchor ");
+ is(dt.getData("URL"), "http://www.mozilla.org#anchor", "uri-list with spaces and hash");
+
+ // ensure that setDataAt works the same way
+ dt.mozSetDataAt("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n", 0);
+ checkURL(dt, "http://www.xulplanet.com",
+ "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n",
+ 0, "uri-list mix setDataAt");
+
+ // now test adding multiple items to be dragged using the setDataAt method
+ dt.clearData();
+ dt.mozSetDataAt("text/plain", "First Item", 0);
+ dt.mozSetDataAt("text/plain", "Second Item", 1);
+ expectError(() => dt.mozSetDataAt("text/plain", "Some Text", 3),
+ "IndexSizeError", "setDataAt index too high with two items");
+ is(dt.mozItemCount, 2, "setDataAt item itemCount");
+ checkOneDataItem(dt, ["text/plain"], ["First Item"], 0, "setDataAt item at index 0");
+ checkOneDataItem(dt, ["text/plain"], ["Second Item"], 1, "setDataAt item at index 1");
+
+ dt.mozSetDataAt("text/html", "<em>First Item</em>", 0);
+ dt.mozSetDataAt("text/html", "<em>Second Item</em>", 1);
+ is(dt.mozItemCount, 2, "setDataAt two types item itemCount");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["First Item", "<em>First Item</em>"], 0, "setDataAt two types item at index 0");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["Second Item", "<em>Second Item</em>"], 1, "setDataAt two types item at index 1");
+
+ dt.mozSetDataAt("text/html", "<em>Changed First Item</em>", 0);
+ dt.mozSetDataAt("text/plain", "Changed Second Item", 1);
+ is(dt.mozItemCount, 2, "changed with setDataAt item itemCount");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["First Item", "<em>Changed First Item</em>"], 0, "changed with setDataAt item at index 0");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setDataAt item at index 1");
+
+ dt.setData("text/html", "Changed with setData");
+ is(dt.mozItemCount, 2, "changed with setData");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["First Item", "Changed with setData"], 0, "changed with setData item at index 0");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setData item at index 1");
+
+ dt.mozSetDataAt("application/-moz-node", "draggable", 2);
+ is(dt.mozItemCount, 3, "setDataAt node itemCount");
+ checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 2, "setDataAt node item at index 2");
+
+ // Try to add and then remove a non-string type to the DataTransfer and ensure
+ // that the type appears in DataTransfer.types.
+ {
+ dt.mozSetDataAt("application/-x-body", document.body, 0);
+ let found = false;
+ for (let i = 0; i < dt.types.length; ++i) {
+ if (dt.types[i] == "application/-x-body") {
+ found = true;
+ break;
+ }
+ }
+ ok(found, "Data should appear in datatransfer.types despite having a non-string type");
+ dt.mozClearDataAt("application/-x-body", 0);
+ }
+
+ dt.mozClearDataAt("text/html", 1);
+ is(dt.mozItemCount, 3, "clearDataAt itemCount");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["First Item", "Changed with setData"], 0, "clearDataAt item at index 0");
+ checkOneDataItem(dt, ["text/plain"], ["Changed Second Item"], 1, "clearDataAt item at index 1");
+
+ dt.mozClearDataAt("text/plain", 1);
+ is(dt.mozItemCount, 2, "clearDataAt last type itemCount");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["First Item", "Changed with setData"], 0, "clearDataAt last type at index 0");
+ checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 1, "clearDataAt last type item at index 2");
+ expectError(() => dt.mozGetDataAt("text/plain", 2),
+ "IndexSizeError", "getDataAt after item removed index too high");
+
+ dt.mozSetDataAt("text/unknown", "Unknown type", 2);
+ dt.mozSetDataAt("text/unknown", "Unknown type", 1);
+ is(dt.mozItemCount, 3, "add unknown type");
+ checkOneDataItem(dt, ["application/-moz-node", "text/unknown"],
+ ["draggable", "Unknown type"], 1, "add unknown type item at index 1");
+ checkOneDataItem(dt, ["text/unknown"], ["Unknown type"], 2, "add unknown type item at index 2");
+
+ dt.mozClearDataAt("", 1);
+ is(dt.mozItemCount, 2, "clearDataAt empty string");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["First Item", "Changed with setData"], 0, "clearDataAt empty string item at index 0");
+ checkOneDataItem(dt, ["text/unknown"],
+ ["Unknown type"], 1, "clearDataAt empty string item at index 1");
+
+ // passing a format that doesn't exist to clearData or clearDataAt should just
+ // do nothing
+ dt.clearData("text/something");
+ dt.mozClearDataAt("text/something", 1);
+ is(dt.mozItemCount, 2, "clearData type that does not exist");
+ checkOneDataItem(dt, ["text/plain", "text/html"],
+ ["First Item", "Changed with setData"], 0, "clearData type that does not exist item at index 0");
+ checkOneDataItem(dt, ["text/unknown"],
+ ["Unknown type"], 1, "clearData type that does not exist item at index 1");
+
+ expectError(() => dt.mozClearDataAt("text/plain", 3),
+ "IndexSizeError", "clearData index too high with two items");
+
+ // ensure that clearData() removes all data associated with the first item, but doesn't
+ // shift the second item down into the first item's slot.
+ dt.clearData();
+ is(dt.mozItemCount, 2, "clearData no argument with multiple items itemCount");
+ checkOneDataItem(dt, [], [], 0,
+ "clearData no argument with multiple items item at index 0");
+ checkOneDataItem(dt, ["text/unknown"],
+ ["Unknown type"], 1, "clearData no argument with multiple items item at index 1");
+
+ // remove tha remaining data in index 1. As index 0 is empty at this point, this will actually
+ // drop mozItemCount to 0. (XXX: This is because of spec-compliance reasons related
+ // to the more-recent dt.item API. It's an unfortunate, but hopefully rare edge case)
+ dt.mozClearDataAt("", 1);
+ is(dt.mozItemCount, 0, "all data cleared");
+
+ // now check the effectAllowed and dropEffect properties
+ is(dt.dropEffect, "none", "initial dropEffect");
+ is(dt.effectAllowed, "uninitialized", "initial effectAllowed");
+
+ ["copy", "none", "link", "", "other", "copyMove", "all", "uninitialized", "move"].forEach(
+ function (i) {
+ dt.dropEffect = i;
+ is(dt.dropEffect, i == "" || i == "other" || i == "copyMove" ||
+ i == "all" || i == "uninitialized" ? "link" : i,
+ "dropEffect set to " + i);
+ is(dt.effectAllowed, "uninitialized", "effectAllowed not modified by dropEffect set to " + i);
+ }
+ );
+
+ ["move", "copy", "link", "", "other", "moveCopy", "copyMove",
+ "linkMove", "copyLink", "all", "uninitialized", "none"].forEach(
+ function (i) {
+ dt.effectAllowed = i;
+ is(dt.dropEffect, "move", "dropEffect not modified by effectAllowed set to " + i);
+ is(dt.effectAllowed, i == "" || i == "other" || i == "moveCopy" ? "link" : i,
+ "effectAllowed set to " + i);
+ }
+ );
+}
+
+function doDragStartLink(event)
+{
+ var dt = event.dataTransfer;
+ checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
+ "text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial link");
+
+ is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial link item count");
+ is(dt.getData("text/uri-list"), "http://www.mozilla.org/", "link text/uri-list");
+ is(dt.getData("text/plain"), "http://www.mozilla.org/", "link text/plain");
+
+ event.preventDefault();
+
+ gExtraDragTests++;
+}
+
+function doDragStartImage(event)
+{
+ var dataurl = $("image").src;
+
+ var dt = event.dataTransfer;
+ checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
+ "text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial image");
+
+ is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial image item count");
+ is(dt.getData("text/uri-list"), dataurl, "image text/uri-list");
+ is(dt.getData("text/plain"), dataurl, "image text/plain");
+
+ event.preventDefault();
+
+ gExtraDragTests++;
+}
+
+function doDragStartInput(event)
+{
+ var dt = event.dataTransfer;
+ checkTypes(dt, ["text/plain"], 0, "initial input");
+
+ is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial input item count");
+// is(dt.getData("text/plain"), "Text", "input text/plain");
+
+// event.preventDefault();
+}
+
+
+function doDragStartInShadowRoot(event)
+{
+ is(event.type, "dragstart", "shadow root dragstart event type");
+ is(event.target, $("shadow_host_containing_draggable"), "shadow root dragstart event target");
+ is(event.bubbles, true, "shadow root dragstart event bubbles");
+ is(event.cancelable, true, "shadow root dragstart event cancelable");
+
+ event.preventDefault();
+
+ gExtraDragTests++;
+}
+function doDragStartSynthetic(event)
+{
+ is(event.type, "dragstart", "synthetic dragstart event type");
+
+ var dt = event.dataTransfer;
+ todo(dt instanceof DataTransfer, "synthetic dragstart dataTransfer is DataTransfer");
+// Uncomment next line once the todo instanceof above is fixed.
+// checkTypes(dt, [], 0, "synthetic dragstart");
+
+ is(event.detail, 1, "synthetic dragstart detail");
+ is(event.screenX, 40, "synthetic dragstart screenX");
+ is(event.screenY, 35, "synthetic dragstart screenY");
+ is(event.clientX, 20, "synthetic dragstart clientX");
+ is(event.clientY, 15, "synthetic dragstart clientY");
+ is(event.ctrlKey, false, "synthetic dragstart ctrlKey");
+ is(event.altKey, true, "synthetic dragstart altKey");
+ is(event.shiftKey, false, "synthetic dragstart shiftKey");
+ is(event.metaKey, false, "synthetic dragstart metaKey");
+ is(event.button, 0, "synthetic dragstart button ");
+ is(event.relatedTarget, null, "synthetic dragstart relatedTarget");
+
+// Uncomment next two lines once the todo instanceof above is fixed.
+// dt.setData("text/plain", "Text");
+// is(dt.getData("text/plain"), "Text", "synthetic dragstart data is set after adding");
+}
+
+function doDragOverSynthetic(event)
+{
+ is(event.type, "dragover", "synthetic dragover event type");
+
+ var dt = event.dataTransfer;
+ todo(dt instanceof DataTransfer, "synthetic dragover dataTransfer is DataTransfer");
+// Uncomment next line once the todo instanceof above is fixed.
+// checkTypes(dt, [], 0, "synthetic dragover");
+
+ is(event.detail, 0, "synthetic dragover detail");
+ is(event.screenX, 40, "synthetic dragover screenX");
+ is(event.screenY, 35, "synthetic dragover screenY");
+ is(event.clientX, 20, "synthetic dragover clientX");
+ is(event.clientY, 15, "synthetic dragover clientY");
+ is(event.ctrlKey, true, "synthetic dragover ctrlKey");
+ is(event.altKey, false, "synthetic dragover altKey");
+ is(event.shiftKey, true, "synthetic dragover shiftKey");
+ is(event.metaKey, true, "synthetic dragover metaKey");
+ is(event.button, 2, "synthetic dragover button");
+ is(event.relatedTarget, document.documentElement, "synthetic dragover relatedTarget");
+
+// Uncomment next two lines once the todo instanceof above is fixed.
+// dt.setData("text/plain", "Text");
+// is(dt.getData("text/plain"), "Text", "synthetic dragover data is set after adding");
+}
+
+function onDragStartDraggable(event)
+{
+ var dt = event.dataTransfer;
+ ok(SpecialPowers.wrap(dt).mozItemCount == 0 && dt.types.length == 0 && event.originalTarget == gDragInfo.target, gDragInfo.testid);
+
+ event.preventDefault();
+ gExtraDragTests++;
+}
+
+// Expects dt wrapped in SpecialPowers
+function checkOneDataItem(dt, expectedtypes, expecteddata, index, testid)
+{
+ checkTypes(dt, expectedtypes, index, testid);
+ for (var f = 0; f < expectedtypes.length; f++) {
+ if (index == 0)
+ is(dt.getData(expectedtypes[f]), expecteddata[f], testid + " getData " + expectedtypes[f]);
+ is(dt.mozGetDataAt(expectedtypes[f], index), expecteddata[f] ? expecteddata[f] : null,
+ testid + " getDataAt " + expectedtypes[f]);
+ }
+}
+
+function checkTypes(dt, expectedtypes, index, testid)
+{
+ if (index == 0) {
+ var types = dt.types;
+ is(types.length, expectedtypes.length, testid + " types length");
+ for (var f = 0; f < expectedtypes.length; f++) {
+ is(types[f], expectedtypes[f], testid + " " + types[f] + " check");
+ }
+ }
+
+ types = SpecialPowers.wrap(dt).mozTypesAt(index);
+ is(types.length, expectedtypes.length, testid + " typesAt length");
+ for (var f = 0; f < expectedtypes.length; f++) {
+ is(types[f], expectedtypes[f], testid + " " + types[f] + " at " + index + " check");
+ }
+}
+
+// Expects dt wrapped in SpecialPowers
+function checkURL(dt, url, fullurllist, index, testid)
+{
+ is(dt.getData("text/uri-list"), fullurllist, testid + " text/uri-list");
+ is(dt.getData("URL"), url, testid + " URL");
+ is(dt.mozGetDataAt("text/uri-list", 0), fullurllist, testid + " text/uri-list");
+ is(dt.mozGetDataAt("URL", 0), fullurllist, testid + " URL");
+}
+
+function expectError(fn, eid, testid)
+{
+ var error = "";
+ try {
+ fn();
+ } catch (ex) {
+ error = ex.name;
+ }
+ is(error, eid, testid + " causes exception " + eid);
+}
+
+</script>
+
+</head>
+
+<body style="height: 300px; overflow: auto;" onload="setTimeout(runTests, 0)">
+
+<div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> bit of text.</div>
+
+<fieldset>
+<a id="link" href="http://www.mozilla.org/" ondragstart="doDragStartLink(event)">mozilla.org</a>
+</fieldset>
+
+<label>
+<img id="image" src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"
+ ondragstart="doDragStartImage(event)">
+</label>
+
+<input id="input" value="Text in a box" ondragstart="doDragStartInput(event)">
+
+<div ondragstart="onDragStartDraggable(event)">
+ <div id="dragtrue" draggable="true">
+ This is a <span id="spantrue">draggable</span> area.
+ </div>
+ <div id="dragfalse" draggable="false">
+ This is a <span id="spanfalse">non-draggable</span> area.
+ </div>
+</div>
+
+<!--iframe src="http://www.mozilla.org" width="400" height="400"></iframe-->
+
+<div id="synthetic" ondragstart="doDragStartSynthetic(event)">Synthetic Event Dispatch</div>
+<div id="synthetic2" ondragover="doDragOverSynthetic(event)">Synthetic Event Dispatch</div>
+
+<div draggable="true" id="shadow_host_containing_draggable"></div>
+
+<script>
+shadow_host_containing_draggable.attachShadow({ mode: 'open' }).innerHTML =
+`<span>Inside shadow root</span>`;
+shadow_host_containing_draggable.addEventListener("dragstart", doDragStartInShadowRoot);
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_error_events.html b/dom/events/test/test_error_events.html
new file mode 100644
index 0000000000..1d47e5398b
--- /dev/null
+++ b/dom/events/test/test_error_events.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for error events being ErrorEvent</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ setup({allow_uncaught_exception:true});
+ var errorEvent;
+ var file;
+ var line;
+ var msg;
+ var column;
+ var error;
+ window.addEventListener("error", function(e) {
+ errorEvent = e;
+ }, {once: true});
+ var oldOnerror = window.onerror;
+ window.onerror = function(message, filename, lineno, columnno, errorObject) {
+ window.onerror = oldOnerror;
+ file = filename;
+ line = lineno;
+ msg = message;
+ column = columnno;
+ error = errorObject;
+ }
+ var thrown = new Error("hello");
+ throw thrown;
+</script>
+<script>
+ generate_tests(assert_equals, [
+ [ "Event filename", errorEvent.filename, location.href ],
+ [ "Callback filename", file, location.href ],
+ [ "Event line number", errorEvent.lineno, 27 ],
+ [ "Callback line number", line, 27 ],
+ [ "Event message", errorEvent.message, "Error: hello" ],
+ [ "Callback message", msg, "Error: hello" ],
+ [ "Event error-object", errorEvent.error, thrown],
+ [ "Callback error-object", error, thrown ],
+ [ "Event column", errorEvent.colno, 16 ],
+ [ "Callback column", column, 16 ]
+ ]);
+</script>
+<script>
+ var workerLocation = location.protocol + "//" + location.host +
+ location.pathname.replace("test_error_events.html", "error_event_worker.js");
+ var eventFileTest = async_test("Worker event filename");
+ var eventLineTest = async_test("Worker event line number");
+ var eventMessageTest = async_test("Worker event message");
+ var callbackFileTest = async_test("Worker callback filename");
+ var callbackLineTest = async_test("Worker callback line number");
+ var callbackMessageTest = async_test("Worker callback message");
+ var w = new Worker("error_event_worker.js");
+ w.addEventListener("message", function(msg) {
+ if (msg.data.type == "event") {
+ eventFileTest.step(function() { assert_equals(msg.data.filename, workerLocation); });
+ eventFileTest.done();
+ eventLineTest.step(function() { assert_equals(msg.data.lineno, 19); });
+ eventLineTest.done();
+ eventMessageTest.step(function() { assert_equals(msg.data.message, "Error: workerhello"); });
+ eventMessageTest.done();
+ } else {
+ callbackFileTest.step(function() { assert_equals(msg.data.filename, workerLocation); });
+ callbackFileTest.done();
+ callbackLineTest.step(function() { assert_equals(msg.data.lineno, 19); });
+ callbackLineTest.done();
+ callbackMessageTest.step(function() { assert_equals(msg.data.message, "Error: workerhello"); });
+ callbackMessageTest.done();
+ }
+ });
+</script>
diff --git a/dom/events/test/test_eventTimeStamp.html b/dom/events/test/test_eventTimeStamp.html
new file mode 100644
index 0000000000..a0a52409a0
--- /dev/null
+++ b/dom/events/test/test_eventTimeStamp.html
@@ -0,0 +1,116 @@
+<!doctype html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=77992
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Event.timeStamp (Bug 77992)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=77992">Mozilla Bug 77992</a>
+<p id="display"></p>
+<pre id="test">
+<script type="text/js-worker" id="worker-src">
+ // Simply returns the event timestamp
+ onmessage = function(evt) {
+ postMessage(evt.timeStamp + performance.timeOrigin);
+ }
+</script>
+<script type="text/js-worker" id="shared-worker-src">
+ // Simply returns the event timestamp
+ onconnect = function(evt) {
+ var port = evt.ports[0];
+ port.onmessage = function(messageEvt) {
+ port.postMessage(messageEvt.timeStamp + performance.timeOrigin);
+ };
+ };
+</script>
+<script type="application/javascript">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+// This file performs tests that normalize the timeOrigin within a worker
+// and compare it to the page. When this occurs, time can appear to go backwards.
+// This is a known (and accepted) regression of privacy.reduceTimerPrecision so
+// we need to turn it off.
+SpecialPowers.pushPrefEnv({ "set": [
+ ["privacy.reduceTimerPrecision", false]
+ ]}, testRegularEvents);
+
+// Event.timeStamp should be relative to the time origin which is:
+//
+// Non-worker context: navigation start
+// Dedicated worker: navigation start of the document that created the worker
+// Shared worker: creation time of the shared worker
+//
+// See: https://w3c.github.io/web-performance/specs/HighResolutionTime2/Overview.html#sec-time-origin
+
+function testRegularEvents() {
+ var timeBeforeEvent = performance.now();
+ document.getElementById('test').addEventListener("click", function(evt) {
+ var timeAfterEvent = performance.now();
+ ok(evt.timeStamp >= timeBeforeEvent &&
+ evt.timeStamp <= timeAfterEvent,
+ "Event timestamp (" + evt.timeStamp + ") is in expected range: [" +
+ timeBeforeEvent + ", " + timeAfterEvent + "]");
+ testWorkerEvents();
+ });
+ document.getElementById('test').click();
+}
+
+function testWorkerEvents() {
+ var blob = new Blob([ document.getElementById("worker-src").textContent ],
+ { type: "text/javascript" });
+ var worker = new Worker(URL.createObjectURL(blob));
+ worker.onmessage = function(evt) {
+ var timeAfterEvent = performance.now() + performance.timeOrigin;
+ ok(evt.data >= timeBeforeEvent &&
+ evt.data <= timeAfterEvent,
+ "Event timestamp in dedicated worker (" + evt.data +
+ ") is in expected range: [" +
+ timeBeforeEvent + ", " + timeAfterEvent + "]");
+ worker.terminate();
+ testSharedWorkerEvents();
+ };
+ var timeBeforeEvent = performance.now() + performance.timeOrigin;
+ worker.postMessage("");
+}
+
+function testSharedWorkerEvents() {
+ var blob =
+ new Blob([ document.getElementById("shared-worker-src").textContent ],
+ { type: "text/javascript" });
+ // Delay creation of worker slightly so it is easier to distinguish
+ // shared worker creation time from this document's navigation start
+ setTimeout(function() {
+ var timeBeforeEvent = performance.now() + performance.timeOrigin;
+ var worker = new SharedWorker(URL.createObjectURL(blob));
+ worker.port.onmessage = function(evt) {
+ var timeAfterEvent = performance.now() + performance.timeOrigin;
+ ok(evt.data >= timeBeforeEvent &&
+ evt.data <= timeAfterEvent,
+ "Event timestamp in shared worker (" + evt.data +
+ ") is in expected range: [" +
+ timeBeforeEvent + ", " + timeAfterEvent + "]");
+ worker.port.close();
+ finishTests();
+ };
+ worker.port.start();
+ worker.port.postMessage("");
+ }, 500);
+}
+
+var finishTests = function() {
+ SimpleTest.finish();
+};
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_event_handler_cc.html b/dom/events/test/test_event_handler_cc.html
new file mode 100644
index 0000000000..b2ad5aa088
--- /dev/null
+++ b/dom/events/test/test_event_handler_cc.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for cycle collection of event handlers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ function listener() {}
+
+ function make_weak_ref(obj) {
+ let m = new WeakMap;
+ m.set(obj, {});
+ return m;
+ }
+
+ function weak_ref_dead(r) {
+ return SpecialPowers.nondeterministicGetWeakMapKeys(r).length == 0;
+ }
+
+ function setupTarget1() {
+ let ifr = document.getElementById("target1");
+ let doc = ifr.contentDocument;
+ let b = doc.createElement("button");
+ doc.body.appendChild(b);
+ b.onclick = listener;
+ ifr.remove();
+ return make_weak_ref(b);
+ }
+
+ function setupTarget2() {
+ let ifr = document.getElementById("target2");
+ let doc = ifr.contentDocument;
+ let b = doc.createElement("button");
+ doc.body.appendChild(b);
+ let setFunc = new ifr.contentWindow.Function(`
+ var b = document.querySelector("button");
+ var proto = parent.HTMLElement.prototype;
+ var setter = Object.getOwnPropertyDescriptor(proto, "onclick").set;
+ // Here the current global (and hence CallbackObject global) will be
+ // the parent, the callback will be a known-live thing from the
+ // parent, but the incumbent global will be the child.
+ setter.call(b, parent.listener);
+ `);
+ setFunc();
+ ifr.remove();
+ return make_weak_ref(b);
+ }
+
+ addLoadEvent(function() {
+ let ref1 = setupTarget1();
+ let ref2 = setupTarget2();
+ SpecialPowers.exactGC(function () {
+ SpecialPowers.forceCC();
+ SpecialPowers.forceGC();
+ SpecialPowers.forceGC();
+
+ ok(weak_ref_dead(ref1),
+ "Should collect cycle through callback global");
+ ok(weak_ref_dead(ref2),
+ "Should collect cycle through incumbent global");
+
+ SimpleTest.finish();
+ });
+ });
+ </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<iframe id="target1"></iframe>
+<iframe id="target2"></iframe>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/events/test/test_event_screenXY_in_cross_origin_iframe.html b/dom/events/test/test_event_screenXY_in_cross_origin_iframe.html
new file mode 100644
index 0000000000..0a84579f20
--- /dev/null
+++ b/dom/events/test/test_event_screenXY_in_cross_origin_iframe.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title></title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/paint_listener.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js"></script>
+<iframe width=100></iframe>
+<iframe width=100></iframe>
+<script>
+const utils = SpecialPowers.DOMWindowUtils;
+
+function synthesizeNativeMouseClick(aElement, aScreenX, aScreenY) {
+ return new Promise(resolve => {
+ utils.sendNativeMouseEvent(aScreenX, aScreenY,
+ nativeMouseDownEventMsg(), 0, aElement, () => {
+ utils.sendNativeMouseEvent(aScreenX, aScreenY,
+ nativeMouseUpEventMsg(),
+ 0,
+ aElement, resolve);
+ });
+ });
+}
+
+function getScreenPosition(aElement, aOffsetX, aOffsetY) {
+ const rect = aElement.getBoundingClientRect();
+ const x = aOffsetX + window.mozInnerScreenX + rect.left;
+ const y = aOffsetY + window.mozInnerScreenY + rect.top;
+ const scale = utils.screenPixelsPerCSSPixel;
+ return [Math.round(x * scale), Math.round(y * scale)];
+}
+
+add_task(async () => {
+ await SimpleTest.promiseFocus();
+
+ const loadsPromise = new Promise(resolve => {
+ let readyInSameOriginIFrame = false;
+ let readyInCrossOriginIFrame = false;
+ window.addEventListener("message", function listener(event) {
+ if (event.data == "ready") {
+ if (event.origin == location.origin) {
+ readyInSameOriginIFrame = true;
+ }
+ if (event.origin == "https://example.com") {
+ readyInCrossOriginIFrame = true;
+ }
+ }
+ if (readyInSameOriginIFrame && readyInCrossOriginIFrame) {
+ window.removeEventListener("message", listener);
+ resolve();
+ }
+ });
+ });
+
+ const iframes = document.querySelectorAll("iframe");
+ iframes[0].src = "file_event_screenXY.html";
+ iframes[1].src = "https://example.com/tests/dom/events/test/file_event_screenXY.html";
+
+ await loadsPromise;
+
+ // Wait for APZ state stable so that mouse event handling APZ works properly
+ // in out-of-process iframes.
+ await new Promise(resolve => waitForApzFlushedRepaints(resolve));
+
+ const promiseForSameOrigin = new Promise(resolve => {
+ window.addEventListener("message", event => {
+ is(event.origin, location.origin, "origin should be the same as parent");
+ resolve(event.data);
+ }, { once: true });
+ });
+
+ // NOTE: synthesizeMouseAtCenter doesn't work for OOP iframes (bug 1528935),
+ // so we use synthesizeNativeMouseClick instead.
+ const [expectedScreenXInSameOrigin, expectedScreenYInSameOrigin] =
+ getScreenPosition(iframes[0], 10, 10);
+ await synthesizeNativeMouseClick(iframes[0], expectedScreenXInSameOrigin, expectedScreenYInSameOrigin);
+
+ const eventInSameOrigin = await promiseForSameOrigin;
+ is(eventInSameOrigin.screenX, expectedScreenXInSameOrigin,
+ "event.screenX should be the same");
+ is(eventInSameOrigin.screenY, expectedScreenYInSameOrigin,
+ "event.screenY should be the same");
+
+ const [expectedScreenXInCrossOrigin, expectedScreenYInCrossOrigin] =
+ getScreenPosition(iframes[1], 10, 10);
+ await synthesizeNativeMouseClick(iframes[0], expectedScreenXInCrossOrigin, expectedScreenYInCrossOrigin);
+
+ const promiseForCrossOrigin = new Promise(resolve => {
+ window.addEventListener("message", event => {
+ is(event.origin, "https://example.com", "origin should be example.com");
+ resolve(event.data);
+ }, { once: true });
+ });
+
+ const eventInCrossOrigin = await promiseForCrossOrigin;
+ is(eventInCrossOrigin.screenX, expectedScreenXInCrossOrigin,
+ "even.screenX should be the same");
+ is(eventInCrossOrigin.screenY, expectedScreenYInCrossOrigin,
+ "even.screenY should be the same");
+
+ is(eventInSameOrigin.screenY, eventInCrossOrigin.screenY,
+ "event.screenY in both iframes should be the same");
+ // Sanity checks to make sure client{X,Y} are the same.
+ is(eventInSameOrigin.clientX, eventInCrossOrigin.clientX,
+ "event.clientX in both iframes should be the same");
+ is(eventInSameOrigin.clientY, eventInCrossOrigin.clientY,
+ "event.clientY in both iframes should be the same");
+});
+</script>
diff --git a/dom/events/test/test_eventctors.html b/dom/events/test/test_eventctors.html
new file mode 100644
index 0000000000..a81e1560fe
--- /dev/null
+++ b/dom/events/test/test_eventctors.html
@@ -0,0 +1,936 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=675884
+-->
+<head>
+ <title>Test for Bug 675884</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=675884">Mozilla Bug 675884</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 675884 **/
+
+var receivedEvent;
+document.addEventListener("hello", function(e) { receivedEvent = e; }, true);
+
+function isMethodResultInitializer(aPropName)
+{
+ return aPropName.startsWith("modifier");
+}
+
+function getPropValue(aEvent, aPropName)
+{
+ if (aPropName.startsWith("modifier")) {
+ return aEvent.getModifierState(aPropName.substr("modifier".length));
+ }
+ return aEvent[aPropName];
+}
+
+// Event
+var e;
+var ex = false;
+try {
+ e = new Event();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+try {
+ e = new Event("foo", 123);
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+try {
+ e = new Event("foo", "asdf");
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+
+try {
+ e = new Event("foo", false);
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "2nd parameter should be an object!");
+ex = false;
+
+
+e = new Event("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+e.isTrusted = true;
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+
+try {
+ e.__defineGetter__("isTrusted", function() { return true });
+} catch (exp) {
+ ex = true;
+}
+ok(ex, "Shouldn't be able to re-define the getter for isTrusted.");
+ex = false;
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+
+ok(!("isTrusted" in Object.getPrototypeOf(e)))
+
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+document.dispatchEvent(e);
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+is(receivedEvent, e, "Wrong event!");
+
+e = new Event("hello", null);
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+document.dispatchEvent(e);
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+is(receivedEvent, e, "Wrong event!");
+
+e = new Event("hello", undefined);
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+document.dispatchEvent(e);
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+is(receivedEvent, e, "Wrong event!");
+
+e = new Event("hello", {});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+document.dispatchEvent(e);
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+is(receivedEvent, e, "Wrong event!");
+
+e = new Event("hello", { bubbles: true, cancelable: true });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// CustomEvent
+
+try {
+ e = new CustomEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+e = new CustomEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new CustomEvent("hello", { bubbles: true, cancelable: true, detail: window });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.detail, window , "Wrong event.detail!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new CustomEvent("hello", { cancelable: true, detail: window });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.detail, window , "Wrong event.detail!");
+
+e = new CustomEvent("hello", { detail: 123 });
+is(e.detail, 123, "Wrong event.detail!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+
+var dict = { get detail() { return document.body } };
+e = new CustomEvent("hello", dict);
+is(e.detail, dict.detail, "Wrong event.detail!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+
+var dict = { get detail() { throw "foo"; } };
+
+try {
+ e = new CustomEvent("hello", dict);
+} catch (exp) {
+ ex = true;
+}
+ok(ex, "Should have thrown an exception!");
+ex = false;
+
+// BlobEvent
+
+try {
+ e = new BlobEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+try {
+ e = new BlobEvent("hello");
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "data attribute is required in init dict");
+ex = false;
+
+var blob = new Blob();
+e = new BlobEvent("hello", {data: blob});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+try {
+ e.__defineGetter__("isTrusted", function() { return true });
+} catch (exp) {
+ ex = true;
+}
+ok(ex, "Shouldn't be able to re-define the getter for isTrusted.");
+ex = false;
+ok(!e.isTrusted, "BlobEvent shouldn't be trusted!");
+
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new BlobEvent("hello", { bubbles: true, cancelable: true, data: blob });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.data, blob , "Wrong event.data!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new BlobEvent("hello", {data: blob});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event should be cancelable1!");
+is(e.data, blob , "Wrong event.data!");
+
+try {
+ e = new BlobEvent("hello", { data: null });
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "data attribute cannot be null");
+ex = false;
+blob = null;
+
+// CloseEvent
+
+try {
+ e = new CloseEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+e = new CloseEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.wasClean, false, "wasClean should be false!");
+is(e.code, 0, "code should be 0!");
+is(e.reason, "", "reason should be ''!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new CloseEvent("hello",
+ { bubbles: true, cancelable: true, wasClean: true, code: 1, reason: "foo" });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.wasClean, true, "wasClean should be true!");
+is(e.code, 1, "code should be 1!");
+is(e.reason, "foo", "reason should be 'foo'!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new CloseEvent("hello",
+ { bubbles: true, cancelable: true, wasClean: true, code: 1 });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.wasClean, true, "wasClean should be true!");
+is(e.code, 1, "code should be 1!");
+is(e.reason, "", "reason should be ''!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+
+// HashChangeEvent
+
+try {
+ e = new HashChangeEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+e = new HashChangeEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.oldURL, "", "oldURL should be ''");
+is(e.newURL, "", "newURL should be ''");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new HashChangeEvent("hello",
+ { bubbles: true, cancelable: true, oldURL: "old", newURL: "new" });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.oldURL, "old", "oldURL should be 'old'");
+is(e.newURL, "new", "newURL should be 'new'");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new HashChangeEvent("hello",
+ { bubbles: true, cancelable: true, newURL: "new" });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.oldURL, "", "oldURL should be ''");
+is(e.newURL, "new", "newURL should be 'new'");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// InputEvent
+
+e = new InputEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.detail, 0, "detail should be 0");
+ok(!e.isComposing, "isComposing should be false");
+
+e = new InputEvent("hi!", { bubbles: true, detail: 5, isComposing: false });
+is(e.type, "hi!", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.detail, 5, "detail should be 5");
+ok(!e.isComposing, "isComposing should be false");
+
+e = new InputEvent("hi!", { cancelable: true, detail: 0, isComposing: true });
+is(e.type, "hi!", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.detail, 0, "detail should be 0");
+ok(e.isComposing, "isComposing should be true");
+
+// KeyboardEvent
+
+try {
+ e = new KeyboardEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "KeyboardEvent: First parameter is required!");
+ex = false;
+
+e = new KeyboardEvent("hello");
+is(e.type, "hello", "KeyboardEvent: Wrong event type!");
+ok(!e.isTrusted, "KeyboardEvent: Event shouldn't be trusted!");
+ok(!e.bubbles, "KeyboardEvent: Event shouldn't bubble!");
+ok(!e.cancelable, "KeyboardEvent: Event shouldn't be cancelable!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "KeyboardEvent: Wrong event!");
+
+var keyboardEventProps =
+[
+ { bubbles: false },
+ { cancelable: false },
+ { view: null },
+ { detail: 0 },
+ { key: "" },
+ { code: "" },
+ { location: 0 },
+ { ctrlKey: false },
+ { shiftKey: false },
+ { altKey: false },
+ { metaKey: false },
+ { modifierAltGraph: false },
+ { modifierCapsLock: false },
+ { modifierFn: false },
+ { modifierFnLock: false },
+ { modifierNumLock: false },
+ { modifierOS: false },
+ { modifierScrollLock: false },
+ { modifierSymbol: false },
+ { modifierSymbolLock: false },
+ { repeat: false },
+ { isComposing: false },
+ { charCode: 0 },
+ { keyCode: 0 },
+ { which: 0 },
+];
+
+var testKeyboardProps =
+[
+ { bubbles: true },
+ { cancelable: true },
+ { view: window },
+ { detail: 1 },
+ { key: "CustomKey" },
+ { code: "CustomCode" },
+ { location: 1 },
+ { ctrlKey: true },
+ { shiftKey: true },
+ { altKey: true },
+ { metaKey: true },
+ { modifierAltGraph: true },
+ { modifierCapsLock: true },
+ { modifierFn: true },
+ { modifierFnLock: true },
+ { modifierNumLock: true },
+ { modifierOS: true },
+ { modifierScrollLock: true },
+ { modifierSymbol: true },
+ { modifierSymbolLock: true },
+ { repeat: true },
+ { isComposing: true },
+ { charCode: 2 },
+ { keyCode: 3 },
+ { which: 4 },
+ { charCode: 5, which: 6 },
+ { keyCode: 7, which: 8 },
+ { keyCode: 9, charCode: 10 },
+ { keyCode: 11, charCode: 12, which: 13 },
+];
+
+var defaultKeyboardEventValues = {};
+for (var i = 0; i < keyboardEventProps.length; ++i) {
+ for (prop in keyboardEventProps[i]) {
+ if (!isMethodResultInitializer(prop)) {
+ ok(prop in e, "keyboardEvent: KeyboardEvent doesn't have property " + prop + "!");
+ }
+ defaultKeyboardEventValues[prop] = keyboardEventProps[i][prop];
+ }
+}
+
+while (testKeyboardProps.length) {
+ var p = testKeyboardProps.shift();
+ e = new KeyboardEvent("foo", p);
+ for (var def in defaultKeyboardEventValues) {
+ if (!(def in p)) {
+ is(getPropValue(e, def), defaultKeyboardEventValues[def],
+ "KeyboardEvent: Wrong default value for " + def + "!");
+ } else {
+ is(getPropValue(e, def), p[def],
+ "KeyboardEvent: Wrong event init value for " + def + "!");
+ }
+ }
+}
+
+// PageTransitionEvent
+
+try {
+ e = new PageTransitionEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+e = new PageTransitionEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.persisted, false, "persisted should be false");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new PageTransitionEvent("hello",
+ { bubbles: true, cancelable: true, persisted: true});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.persisted, true, "persisted should be true");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new PageTransitionEvent("hello", { persisted: true});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.persisted, true, "persisted should be true");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// PopStateEvent
+
+try {
+ e = new PopStateEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+e = new PopStateEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.state, null, "persisted should be null");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new PopStateEvent("hello",
+ { bubbles: true, cancelable: true, state: window});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.state, window, "persisted should be window");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+
+e = new PopStateEvent("hello", { state: window});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.state, window, "persisted should be window");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// UIEvent
+
+try {
+ e = new UIEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+try {
+ e = new UIEvent("foo", { view: {} });
+ e.view.onunload;
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "{} isn't a valid value.");
+ex = false;
+
+try {
+ e = new UIEvent("foo", { view: null });
+} catch(exp) {
+ ex = true;
+}
+ok(!ex, "null is a valid value.");
+is(e.view, null);
+ex = false;
+
+e = new UIEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.detail, 0, "detail should be 0");
+is(e.view, null, "view should be null");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new UIEvent("hello",
+ { bubbles: true, cancelable: true, view: window, detail: 1});
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.detail, 1, "detail should be 1");
+is(e.view, window, "view should be window");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// StorageEvent
+
+e = document.createEvent("StorageEvent");
+ok(e, "Should have created an event!");
+
+try {
+ e = new StorageEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+e = new StorageEvent("hello");
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.key, null, "key should be null");
+is(e.oldValue, null, "oldValue should be null");
+is(e.newValue, null, "newValue should be null");
+is(e.url, "", "url should be ''");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new StorageEvent("hello",
+ { bubbles: true, cancelable: true, key: "key",
+ oldValue: "oldValue", newValue: "newValue", url: "url",
+ storageArea: localStorage });
+is(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.key, "key", "Wrong value");
+is(e.oldValue, "oldValue", "Wrong value");
+is(e.newValue, "newValue", "Wrong value");
+is(e.url, "url", "Wrong value");
+is(e.storageArea, localStorage, "Wrong value");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// MouseEvent
+
+try {
+ e = new MouseEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "MouseEvent: First parameter is required!");
+ex = false;
+
+e = new MouseEvent("hello", { buttons: 1, movementX: 2, movementY: 3});
+is(e.type, "hello", "MouseEvent: Wrong event type!");
+ok(!e.isTrusted, "MouseEvent: Event shouldn't be trusted!");
+ok(!e.bubbles, "MouseEvent: Event shouldn't bubble!");
+ok(!e.cancelable, "MouseEvent: Event shouldn't be cancelable!");
+is(e.buttons, 1);
+is(e.movementX, 2);
+is(e.movementY, 3);
+document.dispatchEvent(e);
+is(receivedEvent, e, "MouseEvent: Wrong event!");
+
+var mouseEventProps =
+[ { screenX: 0 },
+ { screenY: 0 },
+ { clientX: 0 },
+ { clientY: 0 },
+ { ctrlKey: false },
+ { shiftKey: false },
+ { altKey: false },
+ { metaKey: false },
+ { modifierAltGraph: false },
+ { modifierCapsLock: false },
+ { modifierFn: false },
+ { modifierFnLock: false },
+ { modifierNumLock: false },
+ { modifierOS: false },
+ { modifierScrollLock: false },
+ { modifierSymbol: false },
+ { modifierSymbolLock: false },
+ { button: 0 },
+ { buttons: 0 },
+ { relatedTarget: null },
+];
+
+var testProps =
+[
+ { screenX: 1 },
+ { screenY: 2 },
+ { clientX: 3 },
+ { clientY: 4 },
+ { ctrlKey: true },
+ { shiftKey: true },
+ { altKey: true },
+ { metaKey: true },
+ { modifierAltGraph: true },
+ { modifierCapsLock: true },
+ { modifierFn: true },
+ { modifierFnLock: true },
+ { modifierNumLock: true },
+ { modifierOS: true },
+ { modifierScrollLock: true },
+ { modifierSymbol: true },
+ { modifierSymbolLock: true },
+ { button: 5 },
+ { buttons: 6 },
+ { relatedTarget: window }
+];
+
+var defaultMouseEventValues = {};
+for (var i = 0; i < mouseEventProps.length; ++i) {
+ for (prop in mouseEventProps[i]) {
+ if (!isMethodResultInitializer(prop)) {
+ ok(prop in e, "MouseEvent: MouseEvent doesn't have property " + prop + "!");
+ }
+ defaultMouseEventValues[prop] = mouseEventProps[i][prop];
+ }
+}
+
+while (testProps.length) {
+ var p = testProps.shift();
+ e = new MouseEvent("foo", p);
+ for (var def in defaultMouseEventValues) {
+ if (!(def in p)) {
+ is(getPropValue(e, def), defaultMouseEventValues[def],
+ "MouseEvent: Wrong default value for " + def + "!");
+ } else {
+ is(getPropValue(e, def), p[def], "MouseEvent: Wrong event init value for " + def + "!");
+ }
+ }
+}
+
+// PopupBlockedEvent
+
+try {
+ e = new PopupBlockedEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "PopupBlockedEvent: First parameter is required!");
+ex = false;
+
+e = new PopupBlockedEvent("hello");
+is(e.type, "hello", "PopupBlockedEvent: Wrong event type!");
+ok(!e.isTrusted, "PopupBlockedEvent: Event shouldn't be trusted!");
+ok(!e.bubbles, "PopupBlockedEvent: Event shouldn't bubble!");
+ok(!e.cancelable, "PopupBlockedEvent: Event shouldn't be cancelable!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "PopupBlockedEvent: Wrong event!");
+
+e = new PopupBlockedEvent("hello",
+ { requestingWindow: window,
+ popupWindowFeatures: "features",
+ popupWindowName: "name"
+ });
+is(e.requestingWindow, window);
+is(e.popupWindowFeatures, "features");
+is(e.popupWindowName, "name");
+
+// WheelEvent
+
+try {
+ e = new WheelEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "WheelEvent: First parameter is required!");
+ex = false;
+
+e = new WheelEvent("hello", { buttons: 1, movementX: 2, movementY: 3});
+is(e.type, "hello", "WheelEvent: Wrong event type!");
+is(e.buttons, 1);
+is(e.movementX, 2);
+is(e.movementY, 3);
+ok(!e.isTrusted, "WheelEvent: Event shouldn't be trusted!");
+ok(!e.bubbles, "WheelEvent: Event shouldn't bubble!");
+ok(!e.cancelable, "WheelEvent: Event shouldn't be cancelable!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "WheelEvent: Wrong event!");
+
+var wheelEventProps =
+[ { screenX: 0 },
+ { screenY: 0 },
+ { clientX: 0 },
+ { clientY: 0 },
+ { ctrlKey: false },
+ { shiftKey: false },
+ { altKey: false },
+ { metaKey: false },
+ { modifierAltGraph: false },
+ { modifierCapsLock: false },
+ { modifierFn: false },
+ { modifierFnLock: false },
+ { modifierNumLock: false },
+ { modifierOS: false },
+ { modifierScrollLock: false },
+ { modifierSymbol: false },
+ { modifierSymbolLock: false },
+ { button: 0 },
+ { buttons: 0 },
+ { relatedTarget: null },
+ { deltaX: 0.0 },
+ { deltaY: 0.0 },
+ { deltaZ: 0.0 },
+ { deltaMode: 0 }
+];
+
+var testWheelProps =
+[
+ { screenX: 1 },
+ { screenY: 2 },
+ { clientX: 3 },
+ { clientY: 4 },
+ { ctrlKey: true },
+ { shiftKey: true },
+ { altKey: true },
+ { metaKey: true },
+ { modifierAltGraph: true },
+ { modifierCapsLock: true },
+ { modifierFn: true },
+ { modifierFnLock: true },
+ { modifierNumLock: true },
+ { modifierOS: true },
+ { modifierScrollLock: true },
+ { modifierSymbol: true },
+ { modifierSymbolLock: true },
+ { button: 5 },
+ { buttons: 6 },
+ { relatedTarget: window },
+ { deltaX: 7.8 },
+ { deltaY: 9.1 },
+ { deltaZ: 2.3 },
+ { deltaMode: 4 }
+];
+
+var defaultWheelEventValues = {};
+for (var i = 0; i < wheelEventProps.length; ++i) {
+ for (prop in wheelEventProps[i]) {
+ if (!isMethodResultInitializer(prop)) {
+ ok(prop in e, "WheelEvent: WheelEvent doesn't have property " + prop + "!");
+ }
+ defaultWheelEventValues[prop] = wheelEventProps[i][prop];
+ }
+}
+
+while (testWheelProps.length) {
+ var p = testWheelProps.shift();
+ e = new WheelEvent("foo", p);
+ for (var def in defaultWheelEventValues) {
+ if (!(def in p)) {
+ is(getPropValue(e, def), defaultWheelEventValues[def],
+ "WheelEvent: Wrong default value for " + def + "!");
+ } else {
+ is(getPropValue(e, def), p[def], "WheelEvent: Wrong event init value for " + def + "!");
+ }
+ }
+}
+
+// DragEvent
+
+try {
+ e = new DragEvent();
+} catch(exp) {
+ ex = true;
+}
+ok(ex, "DragEvent: First parameter is required!");
+ex = false;
+
+e = new DragEvent("hello", { buttons: 1, movementX: 2, movementY: 3});
+is(e.type, "hello", "DragEvent: Wrong event type!");
+is(e.buttons, 1);
+is(e.movementX, 2);
+is(e.movementY, 3);
+document.dispatchEvent(e);
+is(receivedEvent, e, "DragEvent: Wrong event!");
+
+// TransitionEvent
+e = new TransitionEvent("hello", { propertyName: "color", elapsedTime: 3.5, pseudoElement: "", foobar: "baz" })
+is("propertyName" in e, true, "Transition events have propertyName property");
+is("foobar" in e, false, "Transition events do not copy random properties from event init");
+is(e.propertyName, "color", "Transition event copies propertyName from TransitionEventInit");
+is(e.elapsedTime, 3.5, "Transition event copies elapsedTime from TransitionEventInit");
+is(e.pseudoElement, "", "Transition event copies pseudoElement from TransitionEventInit");
+is(e.bubbles, false, "Lack of bubbles property in TransitionEventInit");
+is(e.cancelable, false, "Lack of cancelable property in TransitionEventInit");
+is(e.type, "hello", "Wrong event type!");
+is(e.isTrusted, false, "Event shouldn't be trusted!");
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+
+// AnimationEvent
+e = new AnimationEvent("hello", { animationName: "bounce3", elapsedTime: 3.5, pseudoElement: "", foobar: "baz" })
+is("animationName" in e, true, "Animation events have animationName property");
+is("foobar" in e, false, "Animation events do not copy random properties from event init");
+is(e.animationName, "bounce3", "Animation event copies animationName from AnimationEventInit");
+is(e.elapsedTime, 3.5, "Animation event copies elapsedTime from AnimationEventInit");
+is(e.pseudoElement, "", "Animation event copies pseudoElement from AnimationEventInit");
+is(e.bubbles, false, "Lack of bubbles property in AnimationEventInit");
+is(e.cancelable, false, "Lack of cancelable property in AnimationEventInit");
+is(e.type, "hello", "Wrong event type!");
+is(e.isTrusted, false, "Event shouldn't be trusted!");
+is(e.eventPhase, Event.NONE, "Wrong event phase");
+
+// InputEvent
+let dataTransfer = new DataTransfer();
+dataTransfer.setData("text/plain", "foo");
+e = new InputEvent("hello", {data: "something data", dataTransfer, inputType: "invalid input type", isComposing: true});
+is(e.type, "hello", "InputEvent should set type attribute");
+is(e.data, "something data", "InputEvent should have data attribute");
+is(e.dataTransfer, dataTransfer, "InputEvent should have the dataTransfer");
+is(e.dataTransfer.getData("text/plain"), "foo", "InputEvent.dataTransfer should keep handling its data");
+try {
+ e.dataTransfer.setData("text/plain", "bar");
+} catch (exp) {
+ ok(false, `InputEvent.dataTransfer.setData("text/plain", "bar") shouldn't fail (${exp})`);
+}
+is(e.dataTransfer.getData("text/plain"), "bar", "InputEvent.dataTransfer should be modified by a call of its setData()");
+is(e.inputType, "invalid input type", "InputEvent should have inputType attribute");
+is(e.isComposing, true, "InputEvent should have isComposing attribute");
+
+dataTransfer = new DataTransfer();
+e = new InputEvent("hello", {data: "", dataTransfer, inputType: "insertText"});
+is(e.data, "", "InputEvent.data should be empty string when empty string is specified explicitly");
+is(e.dataTransfer, dataTransfer, "InputEvent.dataTransfer should have the empty dataTransfer");
+is(e.inputType, "insertText", "InputEvent.inputType should return valid inputType from EditorInputType enum");
+e = new InputEvent("hello", {data: "foo", inputType: "deleteWordBackward"});
+is(e.data, "foo", "InputEvent.data should be the specified string");
+is(e.inputType, "deleteWordBackward", "InputEvent.inputType should return valid inputType from EditorInputType enum");
+e = new InputEvent("hello", {inputType: "formatFontName"});
+is(e.inputType, "formatFontName", "InputEvent.inputType should return valid inputType from EditorInputType enum");
+
+e = new InputEvent("input", {});
+is(e.data, null, "InputEvent.data should be null in default");
+is(e.dataTransfer, null, "InputEvent.dataTransfer should be null in default");
+is(e.inputType, "", "InputEvent.inputType should be empty string in default");
+is(e.isComposing, false, "InputEvent.isComposing should be false in default");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_eventctors.xhtml b/dom/events/test/test_eventctors.xhtml
new file mode 100644
index 0000000000..7906a3c7a8
--- /dev/null
+++ b/dom/events/test/test_eventctors.xhtml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=675884
+-->
+<window title="Mozilla Bug 675884"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=675884"
+ target="_blank">Mozilla Bug 675884</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 675884 **/
+
+ // Most of the tests are in .html file, but test here that
+ // isTrusted is handled correctly in chrome.
+
+ var receivedEvent;
+ document.addEventListener("hello", function(e) { receivedEvent = e; }, true);
+
+ // Event
+ var e;
+ var ex = false;
+ try {
+ e = new Event();
+ } catch(exp) {
+ ex = true;
+ }
+ ok(ex, "First parameter is required!");
+ ex = false;
+
+ e = new Event("hello");
+ is(e.type, "hello", "Wrong event type!");
+ ok(e.isTrusted, "Event should be trusted!");
+ ok(!e.bubbles, "Event shouldn't bubble!");
+ ok(!e.cancelable, "Event shouldn't be cancelable!");
+ document.dispatchEvent(e);
+ is(receivedEvent, e, "Wrong event!");
+
+ ]]>
+ </script>
+</window>
diff --git a/dom/events/test/test_eventctors_sensors.html b/dom/events/test/test_eventctors_sensors.html
new file mode 100644
index 0000000000..9d875e6a21
--- /dev/null
+++ b/dom/events/test/test_eventctors_sensors.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=675884
+-->
+<head>
+ <title>Test for Bug 675884</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=675884">Mozilla Bug 675884</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [
+ ["device.sensors.enabled", true],
+ ["device.sensors.orientation.enabled", true],
+ ["device.sensors.motion.enabled", true],
+ ["device.sensors.proximity.enabled", true],
+ ["device.sensors.ambientLight.enabled", true]
+]}, () => {
+ let receivedEvent;
+ document.addEventListener("hello", function(e) { receivedEvent = e; }, true);
+ // DeviceProximityEvent
+ let e = new DeviceProximityEvent("hello", {min: 0, value: 1, max: 2});
+ is(e.type, "hello", "Wrong event type!");
+ ok(!e.isTrusted, "Event should not be trusted");
+ is(e.value, 1, "value should be 1");
+ is(e.min, 0, "min should be 0");
+ is(e.max, 2, "max should be 2");
+ document.dispatchEvent(e);
+ is(receivedEvent, e, "Wrong event!");
+ e = new DeviceProximityEvent("hello");
+ is(e.value, Infinity, "Uninitialized value should be infinity");
+ is(e.min, -Infinity, "Uninitialized min should be -infinity");
+ is(e.max, Infinity, "Uninitialized max should be infinity");
+
+ // UserProximityEvent
+ e = new UserProximityEvent("hello", {near: true});
+ is(e.type, "hello", "Wrong event type!");
+ ok(!e.isTrusted, "Event should not be trusted");
+ is(e.near, true, "near should be true");
+ document.dispatchEvent(e);
+ is(receivedEvent, e, "Wrong event!");
+
+ // DeviceLightEvent
+ e = new DeviceLightEvent("hello", {value: 1} );
+ is(e.type, "hello", "Wrong event type!");
+ ok(!e.isTrusted, "Event should not be trusted");
+ is(e.value, 1, "value should be 1");
+ document.dispatchEvent(e);
+ is(receivedEvent, e, "Wrong event!");
+ e = new DeviceLightEvent("hello", {value: Infinity} );
+ is(e.value, Infinity, "value should be positive infinity");
+ e = new DeviceLightEvent("hello", {value: -Infinity} );
+ is(e.value, -Infinity, "value should be negative infinity");
+ e = new DeviceLightEvent("hello");
+ is(e.value, Infinity, "Uninitialized value should be positive infinity");
+
+ // DeviceOrientationEvent
+ e = new DeviceOrientationEvent("hello");
+ is(e.type, "hello", "Wrong event type!");
+ ok(!e.isTrusted, "Event should not be trusted");
+ is(e.alpha, null);
+ is(e.beta, null);
+ is(e.gamma, null);
+ is(e.absolute, false);
+
+ e = new DeviceOrientationEvent("hello", { alpha: 1, beta: 2, gamma: 3, absolute: true } );
+ is(e.type, "hello", "Wrong event type!");
+ ok(!e.isTrusted, "Event should not be trusted");
+ is(e.alpha, 1);
+ is(e.beta, 2);
+ is(e.gamma, 3);
+ is(e.absolute, true);
+ document.dispatchEvent(e);
+ is(receivedEvent, e, "Wrong event!");
+
+ // DeviceMotionEvent
+ e = new DeviceMotionEvent("hello");
+ is(e.type, "hello", "Wrong event type!");
+ ok(!e.isTrusted, "Event should not be trusted");
+ is(typeof e.acceleration, "object");
+ is(e.acceleration.x, null);
+ is(e.acceleration.y, null);
+ is(e.acceleration.z, null);
+ is(typeof e.accelerationIncludingGravity, "object");
+ is(e.accelerationIncludingGravity.x, null);
+ is(e.accelerationIncludingGravity.y, null);
+ is(e.accelerationIncludingGravity.z, null);
+ is(typeof e.rotationRate, "object");
+ is(e.rotationRate.alpha, null);
+ is(e.rotationRate.beta, null);
+ is(e.rotationRate.gamma, null);
+ is(e.interval, null);
+
+ SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_eventhandler_scoping.html b/dom/events/test/test_eventhandler_scoping.html
new file mode 100644
index 0000000000..f15238a0c8
--- /dev/null
+++ b/dom/events/test/test_eventhandler_scoping.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for event handler scoping</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var queryResult;
+test(function() {
+ var d = document.createElement("div");
+ d.setAttribute("onclick", "queryResult = querySelector('span')");
+ var s = document.createElement("span");
+ d.appendChild(s);
+ d.dispatchEvent(new Event("click"));
+ assert_equals(queryResult, s, "Should have gotten the right object");
+}, "Test for bareword calls in an event handler using the element as 'this'");
+</script>
diff --git a/dom/events/test/test_focus_abspos.html b/dom/events/test/test_focus_abspos.html
new file mode 100644
index 0000000000..8798c4ed11
--- /dev/null
+++ b/dom/events/test/test_focus_abspos.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>Test for bug 1424633: clicking on an oof descendant focus its focusable ancestor</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<style>
+ #focusable {
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+ }
+ #oof {
+ background-color: green;
+ position: absolute;
+ top: 25px;
+ }
+</style>
+<div tabindex="0" id="focusable">
+ <span id="oof">Absolute</span>
+</div>
+<script>
+window.onload = function() {
+ async_test(function(t) {
+ document.body.offsetTop;
+ setTimeout(t.step_func_done(function() {
+ let span = document.querySelector("#oof");
+ synthesizeMouseAtCenter(span, {type: "mousedown"});
+ assert_equals(document.activeElement, document.querySelector("#focusable"));
+ }), 0);
+ }, "Clicking on an abspos descendant focus its focusable ancestor");
+}
+</script>
diff --git a/dom/events/test/test_focus_blur_on_click_in_cross_origin_iframe.html b/dom/events/test/test_focus_blur_on_click_in_cross_origin_iframe.html
new file mode 100644
index 0000000000..69ab9c20fe
--- /dev/null
+++ b/dom/events/test/test_focus_blur_on_click_in_cross_origin_iframe.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title></title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/paint_listener.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js"></script>
+<iframe width=100></iframe>
+<script>
+SimpleTest.requestLongerTimeout(2);
+
+let state = "start";
+
+const utils = SpecialPowers.DOMWindowUtils;
+
+function synthesizeNativeMouseClick(aElement, aScreenX, aScreenY) {
+ return new Promise(resolve => {
+ utils.sendNativeMouseEvent(aScreenX, aScreenY,
+ nativeMouseDownEventMsg(), 0, aElement, () => {
+ utils.sendNativeMouseEvent(aScreenX, aScreenY,
+ nativeMouseUpEventMsg(),
+ 0,
+ aElement, resolve);
+ });
+ });
+}
+
+function getScreenPosition(aElement, aOffsetX, aOffsetY) {
+ const rect = aElement.getBoundingClientRect();
+ const x = aOffsetX + window.mozInnerScreenX + rect.left;
+ const y = aOffsetY + window.mozInnerScreenY + rect.top;
+ const scale = utils.screenPixelsPerCSSPixel;
+ return [Math.round(x * scale), Math.round(y * scale)];
+}
+
+add_task(async () => {
+ await SimpleTest.promiseFocus();
+
+ const loadsPromise = new Promise((resolve, reject) => {
+ window.addEventListener("message", function listener(event) {
+ if (event.data == "ready") {
+ is(state, "start");
+ state = "ready";
+ resolve();
+ } else {
+ reject("Unexpected message");
+ }
+ }, { once: true });
+ });
+
+ const iframe = document.querySelectorAll("iframe")[0];
+ iframe.src = "https://example.com/tests/dom/events/test/file_focus_blur_on_click_in_cross_origin_iframe.html";
+
+ await loadsPromise;
+
+ // Wait for APZ state stable so that mouse event handling APZ works properly
+ // in out-of-process iframes.
+ await new Promise(resolve => waitForApzFlushedRepaints(resolve));
+
+ // NOTE: synthesizeMouseAtCenter doesn't work for OOP iframes (bug 1528935),
+ // so we use synthesizeNativeMouseClick instead.
+ const [expectedScreenX, expectedScreenY] =
+ getScreenPosition(iframe, 10, 10);
+
+ const firstClickPromise = new Promise((resolve, reject) => {
+ window.addEventListener("message", function listener(event) {
+ if (state == "ready") {
+ if (event.data == "focus") {
+ state = "focusbeforeclick";
+ } else if (event.data == "click") {
+ ok(false, "Focusing failed to complete before mouseup");
+ state = "clickbeforefocus";
+ } else {
+ ok(false, "Unexpected event");
+ }
+ } else if (state == "focusbeforeclick") {
+ is(event.data, "click", "The second event should be 'click'");
+ state = "firstclick";
+ window.removeEventListener("message", listener);
+ resolve();
+ } else if (state == "clickbeforefocus") {
+ is(event.data, "focus", "The second event should be 'click'");
+ state = "firstclick";
+ window.removeEventListener("message", listener);
+ resolve();
+ } else {
+ reject("Unexpected message");
+ }
+ });
+ });
+
+ await synthesizeNativeMouseClick(iframe, expectedScreenX, expectedScreenY);
+
+ await firstClickPromise;
+
+ SimpleTest.requestFlakyTimeout("Waiting for unwanted events that don't exist on success.");
+
+ const secondClickPromise = new Promise((resolve, reject) => {
+ window.addEventListener("message", function listener(event) {
+ if (state == "firstclick") {
+ is(event.data, "click", "The third event should be 'click' again, not 'blur' or 'focus'.");
+ state = "secondclick";
+ setTimeout(function() {
+ // Wait for potential other unwanted events
+ window.removeEventListener("message", listener);
+ resolve()
+ }, 200);
+ } else {
+ reject("Unexpected message " + event.data);
+ }
+ });
+ });
+
+ await synthesizeNativeMouseClick(iframe, expectedScreenX, expectedScreenY);
+
+ await secondClickPromise;
+});
+</script>
diff --git a/dom/events/test/test_focus_blur_on_click_in_deep_cross_origin_iframe.html b/dom/events/test/test_focus_blur_on_click_in_deep_cross_origin_iframe.html
new file mode 100644
index 0000000000..93d28ce159
--- /dev/null
+++ b/dom/events/test/test_focus_blur_on_click_in_deep_cross_origin_iframe.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title></title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/paint_listener.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js"></script>
+<iframe width=100 height=200 scrolling="no"></iframe>
+<script>
+let state = "start";
+
+const utils = SpecialPowers.DOMWindowUtils;
+
+function synthesizeNativeMouseClick(aElement, aScreenX, aScreenY) {
+ return new Promise(resolve => {
+ utils.sendNativeMouseEvent(aScreenX, aScreenY,
+ nativeMouseDownEventMsg(), 0, aElement, () => {
+ utils.sendNativeMouseEvent(aScreenX, aScreenY,
+ nativeMouseUpEventMsg(),
+ 0,
+ aElement, resolve);
+ });
+ });
+}
+
+function getScreenPosition(aElement, aOffsetX, aOffsetY) {
+ const rect = aElement.getBoundingClientRect();
+ const x = aOffsetX + window.mozInnerScreenX + rect.left;
+ const y = aOffsetY + window.mozInnerScreenY + rect.top;
+ const scale = utils.screenPixelsPerCSSPixel;
+ return [Math.round(x * scale), Math.round(y * scale)];
+}
+
+add_task(async () => {
+ await SimpleTest.promiseFocus();
+
+ const loadsPromise = new Promise((resolve, reject) => {
+ let readyMiddle = false;
+ let readyInner = false;
+ window.addEventListener("message", function listener(event) {
+ if (event.data == "middleready") {
+ readyMiddle = true;
+ } else if (event.data == "innerready") {
+ readyInner = true;
+ } else {
+ reject("Unexpected message when waiting for ready " + event.data);
+ }
+ if (readyInner && readyMiddle) {
+ state = "ready";
+ window.removeEventListener("message", listener);
+ resolve();
+ }
+ });
+ });
+
+ const iframe = document.querySelectorAll("iframe")[0];
+ iframe.src = "https://example.com/tests/dom/events/test/file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html";
+
+ await loadsPromise;
+
+ // Wait for APZ state stable so that mouse event handling APZ works properly
+ // in out-of-process iframes.
+ await new Promise(resolve => waitForApzFlushedRepaints(resolve));
+
+ // NOTE: synthesizeMouseAtCenter doesn't work for OOP iframes (bug 1528935),
+ // so we use synthesizeNativeMouseClick instead.
+ const [expectedScreenX, expectedScreenY] =
+ getScreenPosition(iframe, 10, 10);
+
+ const firstClickPromise = new Promise((resolve, reject) => {
+ window.addEventListener("message", function listener(event) {
+ if (state == "ready") {
+ if (event.data == "innerfocus") {
+ state = "innerfocusbeforeclick";
+ } else if (event.data == "innerclick") {
+ ok(false, "Focusing failed to complete before mouseup");
+ state = "innerclickbeforefocus";
+ } else if (event.data == "middlefocus") {
+ is(false, "Should not get an extra middlefocus.");
+ } else {
+ is(event.data, "neverthisevent", "Unexpected event (first click)");
+ }
+ } else if (state == "innerfocusbeforeclick") {
+ is(event.data, "innerclick", "The second event should be 'innerclick'");
+ state = "firstclick";
+ window.removeEventListener("message", listener);
+ resolve();
+ } else if (state == "innerclickbeforefocus") {
+ is(event.data, "innerfocus", "The second event should be 'innerfocus'");
+ state = "firstclick";
+ window.removeEventListener("message", listener);
+ resolve();
+ } else {
+ reject("Unexpected message in firstClickPromise " + event.data);
+ }
+ });
+ });
+
+ await synthesizeNativeMouseClick(iframe, expectedScreenX, expectedScreenY + 110);
+
+ await firstClickPromise;
+
+ SimpleTest.requestFlakyTimeout("Waiting for unwanted events that don't exist on success.");
+
+ const secondClickPromise = new Promise((resolve, reject) => {
+ window.addEventListener("message", function listener(event) {
+ if (state == "firstclick") {
+ is(event.data, "middlefocus", "The third event should be 'middlefocus'.");
+ state = "middlefocusbeforeclick";
+ } else if (state == "middlefocusbeforeclick") {
+ // The order of blur and click is non-deterministic even in the non-Fission case.
+ if (event.data == "middleclick") {
+ state = "waitingforinnerblurafterclick";
+ } else if (event.data == "innerblur") {
+ state = "innerblurbeforeclick";
+ } else {
+ is(event.data, "neverthisevent", "Unexpected event (first click)");
+ }
+ } else if (state == "waitingforinnerblurafterclick") {
+ is(event.data, "innerblur", "The fifth event should be 'innerblur'.");
+ state = "secondclick";
+ setTimeout(function() {
+ // Wait for potential other unwanted events
+ window.removeEventListener("message", listener);
+ resolve()
+ }, 200);
+ } else if (state == "innerblurbeforeclick") {
+ is(event.data, "middleclick", "The fifth event should be 'middleclick'.");
+ state = "secondclick";
+ setTimeout(function() {
+ // Wait for potential other unwanted events
+ window.removeEventListener("message", listener);
+ resolve()
+ }, 200);
+ } else {
+ reject("Unexpected message in secondClickPromise " + event.data);
+ }
+ });
+ });
+
+ await synthesizeNativeMouseClick(iframe, expectedScreenX, expectedScreenY);
+
+ await secondClickPromise;
+});
+</script>
diff --git a/dom/events/test/test_hover_mouseleave.html b/dom/events/test/test_hover_mouseleave.html
new file mode 100644
index 0000000000..aac25f5b51
--- /dev/null
+++ b/dom/events/test/test_hover_mouseleave.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test :hover state on mouseleave.</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<style>
+div {
+ width: 100px;
+ height: 100px;
+}
+</style>
+<div id="target" style="background: green;"></div>
+<div id="outside" style="background: blue;"></div>
+<script>
+SimpleTest.waitForExplicitFinish();
+let mouseLeaveCount = 0;
+let mouseOutCount = 0;
+
+target.addEventListener("mouseleave", () => {
+ if (mouseLeaveCount++ != 0)
+ return;
+ is(target.matches(":hover"), false,
+ "Should've been not hovered on mouseleave");
+ is(outside.matches(":hover"), true,
+ "New target should be hovered on mouseleave");
+ if (mouseOutCount)
+ SimpleTest.finish();
+});
+
+target.addEventListener("mouseout", () => {
+ if (mouseOutCount++ != 0)
+ return;
+ is(target.matches(":hover"), false,
+ "Should've been not hovered on mouseleave");
+ is(outside.matches(":hover"), true,
+ "New target should be hovered on mouseleave");
+ if (mouseLeaveCount)
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForFocus(() => {
+ synthesizeMouseAtCenter(outside, { type: "mousemove" });
+ synthesizeMouseAtCenter(target, { type: "mousemove" });
+ synthesizeMouseAtCenter(outside, { type: "mousemove" });
+});
+</script>
diff --git a/dom/events/test/test_legacy_event.html b/dom/events/test/test_legacy_event.html
new file mode 100644
index 0000000000..82ab2dec6b
--- /dev/null
+++ b/dom/events/test/test_legacy_event.html
@@ -0,0 +1,297 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1236979
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1236979 (events that have legacy alternative versions)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ @keyframes anim1 {
+ 0% { margin-left: 0px }
+ 100% { margin-left: 100px }
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1236979">Mozilla Bug 1236979</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1236979 **/
+
+'use strict';
+SimpleTest.waitForExplicitFinish();
+
+// Array of info-bundles about each legacy event to be tested:
+var gLegacyEventInfo = [
+ {
+ legacy_name: "webkitTransitionEnd",
+ modern_name: "transitionend",
+ trigger_event: triggerShortTransition,
+ },
+ {
+ legacy_name: "webkitAnimationStart",
+ modern_name: "animationstart",
+ trigger_event: triggerShortAnimation,
+ },
+ {
+ legacy_name: "webkitAnimationEnd",
+ modern_name: "animationend",
+ trigger_event: triggerShortAnimation,
+ },
+ {
+ legacy_name: "webkitAnimationIteration",
+ modern_name: "animationiteration",
+ trigger_event: triggerAnimationIteration,
+ }
+];
+
+// EVENT-TRIGGERING FUNCTIONS
+// --------------------------
+// This function triggers a very short (1ms long) transition, which will cause
+// events to fire for the transition ending.
+function triggerShortTransition(node) {
+ node.style.transition = "1ms color linear" ;
+ node.style.color = "purple";
+ // Flush style, so that the above assignment value actually takes effect
+ // in the computed style, so that a transition will get triggered when it
+ // changes.
+ window.getComputedStyle(node).color;
+ node.style.color = "teal";
+}
+
+// This function triggers a very short (1ms long) animation, which will cause
+// events to fire for the animation beginning & ending.
+function triggerShortAnimation(node) {
+ node.style.animation = "anim1 1ms linear";
+}
+
+// This function triggers a very short (10ms long) animation with many
+// iterations, which will cause a start event followed by an iteration event
+// on each subsequent tick, to fire.
+//
+// NOTE: We need the many iterations since if an animation frame coincides
+// with the animation starting or ending we dispatch only the start or end
+// event and not the iteration event.
+function triggerAnimationIteration(node) {
+ node.style.animation = "anim1 10ms linear 20000";
+}
+
+// GENERAL UTILITY FUNCTIONS
+// -------------------------
+// Creates a new div and appends it as a child of the specified parentNode, or
+// (if no parent is specified) as a child of the element with ID 'display'.
+function createChildDiv(parentNode) {
+ if (!parentNode) {
+ parentNode = document.getElementById("display");
+ if (!parentNode) {
+ ok(false, "no 'display' element to append to");
+ }
+ }
+ var div = document.createElement("div");
+ parentNode.appendChild(div);
+ return div;
+}
+
+// Returns an event-handler function, which (when invoked) simply checks that
+// the event's type matches what's expected. If a callback is passed in, then
+// the event-handler will invoke that callback as well.
+function createHandlerWithTypeCheck(expectedEventType, extraHandlerLogic) {
+ var handler = function(e) {
+ is(e.type, expectedEventType,
+ "When an event handler for '" + expectedEventType + "' is invoked, " +
+ "the event's type field should be '" + expectedEventType + "'.");
+ if (extraHandlerLogic) {
+ extraHandlerLogic(e);
+ }
+ }
+ return handler;
+}
+
+// TEST FUNCTIONS
+// --------------
+// These functions expect to be passed an entry from gEventInfo, and they
+// return a Promise which performs the test & resolves when it's complete.
+// The function names all begin with "mp", which stands for "make promise".
+// So e.g. "mpTestLegacyEventSent" means "make a promise to test that the
+// legacy event is sent".
+
+// Tests that the legacy event type is sent, when only a legacy handler is
+// registered.
+function mpTestLegacyEventSent(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ // Create a node & register an event-handler for the legacy event:
+ var div = createChildDiv();
+
+ var handler = createHandlerWithTypeCheck(eventInfo.legacy_name,
+ function() {
+ // When event-handler is done, clean up & resolve:
+ div.remove();
+ resolve();
+ });
+ div.addEventListener(eventInfo.legacy_name, handler);
+
+ // Trigger the event:
+ eventInfo.trigger_event(div);
+ }
+ );
+}
+
+// Test that the modern event type (and only the modern event type) is fired,
+// when listeners of both modern & legacy types are registered. The legacy
+// listener should not be invoked.
+function mpTestModernBeatsLegacy(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ var div = createChildDiv();
+
+ var legacyHandler = function(e) {
+ reject("Handler for legacy event '" + eventInfo.legacy_name +
+ "' should not be invoked when there's a handler registered " +
+ "for both modern & legacy event type on the same node");
+ };
+
+ var modernHandler = createHandlerWithTypeCheck(eventInfo.modern_name,
+ function() {
+ // Indicate that the test has passed (we invoked the modern handler):
+ ok(true, "Handler for modern event '" + eventInfo.modern_name +
+ "' should be invoked when there's a handler registered for " +
+ "both modern & legacy event type on the same node");
+ // When event-handler is done, clean up & resolve:
+ div.remove();
+ resolve();
+ });
+
+ div.addEventListener(eventInfo.legacy_name, legacyHandler);
+ div.addEventListener(eventInfo.modern_name, modernHandler);
+ eventInfo.trigger_event(div);
+ }
+ );
+}
+
+// Test that an event which bubbles may fire listeners of different flavors
+// (modern vs. legacy) at each bubbling level, depending on what's registered
+// at that level.
+function mpTestDiffListenersEventBubbling(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ var grandparent = createChildDiv();
+ var parent = createChildDiv(grandparent);
+ var target = createChildDiv(parent);
+ var didEventFireOnTarget = false;
+ var didEventFireOnParent = false;
+ var eventSentToTarget;
+
+ target.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ ok(e.bubbles, "Expecting event to bubble");
+ eventSentToTarget = e;
+ didEventFireOnTarget = true;
+ }));
+
+ parent.addEventListener(eventInfo.legacy_name,
+ createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
+ is(e, eventSentToTarget,
+ "Same event object should bubble, despite difference in type");
+ didEventFireOnParent = true;
+ }));
+
+ grandparent.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ ok(didEventFireOnTarget,
+ "Event should have fired on child");
+ ok(didEventFireOnParent,
+ "Event should have fired on parent");
+ is(e, eventSentToTarget,
+ "Same event object should bubble, despite difference in type");
+ // Clean up.
+ grandparent.remove();
+ resolve();
+ }));
+
+ eventInfo.trigger_event(target);
+ }
+ );
+}
+
+// Test that an event in the capture phase may fire listeners of different
+// flavors (modern vs. legacy) at each level, depending on what's registered
+// at that level.
+function mpTestDiffListenersEventCapturing(eventInfo) {
+ return new Promise(
+ function(resolve, reject) {
+ var grandparent = createChildDiv();
+ var parent = createChildDiv(grandparent);
+ var target = createChildDiv(parent);
+ var didEventFireOnTarget = false;
+ var didEventFireOnParent = false;
+ var didEventFireOnGrandparent = false;
+ var eventSentToGrandparent;
+
+ grandparent.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ eventSentToGrandparent = e;
+ didEventFireOnGrandparent = true;
+ }), true);
+
+ parent.addEventListener(eventInfo.legacy_name,
+ createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
+ is(e.eventPhase, Event.CAPTURING_PHASE,
+ "event should be in capturing phase");
+ is(e, eventSentToGrandparent,
+ "Same event object should capture, despite difference in type");
+ ok(didEventFireOnGrandparent,
+ "Event should have fired on grandparent");
+ didEventFireOnParent = true;
+ }), true);
+
+ target.addEventListener(eventInfo.modern_name,
+ createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+ is(e.eventPhase, Event.AT_TARGET,
+ "event should be at target phase");
+ is(e, eventSentToGrandparent,
+ "Same event object should capture, despite difference in type");
+ ok(didEventFireOnParent,
+ "Event should have fired on parent");
+ // Clean up.
+ grandparent.remove();
+ resolve();
+ }), true);
+
+ eventInfo.trigger_event(target);
+ }
+ );
+}
+
+// MAIN FUNCTION: Kick off the tests.
+function main() {
+ Promise.resolve().then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestLegacyEventSent))
+ }).then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestModernBeatsLegacy));
+ }).then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventCapturing));
+ }).then(function() {
+ return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventBubbling));
+ }).then(function() {
+ SimpleTest.finish();
+ }).catch(function(reason) {
+ ok(false, "Test failed: " + reason);
+ SimpleTest.finish();
+ });
+}
+
+main();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_legacy_non-primary_click.html b/dom/events/test/test_legacy_non-primary_click.html
new file mode 100644
index 0000000000..6906282aa2
--- /dev/null
+++ b/dom/events/test/test_legacy_non-primary_click.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for dispatching of legacy non-primary click when domain in pref</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<a id="link-test" href="example.org">example link</a>
+<script>
+"use strict";
+SimpleTest.waitForExplicitFinish();
+
+const HACK_PREF = "dom.mouseevent.click.hack.use_legacy_non-primary_dispatch";
+const testEl = document.getElementById("test");
+const linkEl = document.getElementById("link-test");
+let seenClick = false;
+
+SpecialPowers.pushPrefEnv(
+ { set: [[HACK_PREF, document.domain]] },
+ () => {
+ SimpleTest.waitForFocus(() => {
+ // Test seeing the non-primary 'click'
+ document.addEventListener("click", (e) => {
+ ok(true, "Saw 'click' event");
+ seenClick = true;
+ }, { once: true });
+ document.addEventListener("auxclick", (e) => {
+ ok(true, "Saw 'auxclick' event");
+ ok(seenClick, "Saw 'click' event before 'auxclick' event");
+ }, { once: true });
+ synthesizeMouseAtCenter(testEl, { button: 1 });
+
+ // Test preventDefaulting on non-primary 'click'
+ document.addEventListener("click", (e) => {
+ is(e.target, linkEl, "Saw 'click' on link");
+ e.preventDefault();
+ SimpleTest.finish();
+ }, { once: true, capture: true });
+ document.addEventListener("auxclick", (e) => {
+ ok(false, "Shouldn't have got 'auxclick' after preventDefaulting 'click'");
+ }, { once: true });
+ synthesizeMouseAtCenter(linkEl, { button: 1 });
+ });
+ });
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_legacy_touch_api.html b/dom/events/test/test_legacy_touch_api.html
new file mode 100644
index 0000000000..610f787586
--- /dev/null
+++ b/dom/events/test/test_legacy_touch_api.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1412485
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1412485</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1412485 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function testExistenceOfLegacyTouchAPIs(win, enabled) {
+ try {
+ var event = document.createEvent("TouchEvent");
+ ok(event instanceof TouchEvent, "Should be able to create TouchEvent using createEvent.");
+ } catch(ex) {
+ ok(true, "Shouldn't be able create TouchEvent using createEvent.");
+ }
+
+ var targets = [win, win.document, win.document.body];
+ for (target of targets) {
+ is("ontouchstart" in target, enabled, `ontouchstart on target [${enabled}].`);
+ is("ontouchend" in target, enabled, `ontouchend on target [${enabled}].`);
+ is("ontouchmove" in target, enabled, `ontouchmove on target [${enabled}].`);
+ is("ontouchcancel" in target, enabled, `ontouchcancel on target [${enabled}].`);
+ }
+
+ is("createTouch" in win.document, enabled, `createTouch on Document [${enabled}].`);
+ is("createTouchList" in win.document, enabled, `createTouchList on Document [${enabled}].`);
+ }
+
+ function test() {
+ // Test the defaults.
+ testExistenceOfLegacyTouchAPIs(window,
+ navigator.userAgent.includes("Android"));
+
+ // Test explicitly enabling touch APIs.
+ SpecialPowers.pushPrefEnv({"set": [["dom.w3c_touch_events.enabled", 1],
+ ["dom.w3c_touch_events.legacy_apis.enabled", true]]},
+ function() {
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+ iframe.onload = function() {
+ testExistenceOfLegacyTouchAPIs(iframe.contentWindow, true);
+ SimpleTest.finish();
+ }
+ });
+ }
+
+ </script>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1412485">Mozilla Bug 1412485</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_marquee_events.html b/dom/events/test/test_marquee_events.html
new file mode 100644
index 0000000000..22d0eafdf1
--- /dev/null
+++ b/dom/events/test/test_marquee_events.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for bug 1425874</title>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+</head>
+<body>
+ <script>
+ var wasEventCalled;
+ function callEventWithAttributeHandler(element, evt) {
+ wasEventCalled = false;
+ let el = document.createElement(element);
+ el.setAttribute(`on${evt}`, "wasEventCalled = true");
+ el.dispatchEvent(new Event(evt));
+ return wasEventCalled;
+ }
+
+ info("Make sure the EventNameType_HTMLMarqueeOnly events only compile for marquee");
+
+ ok(!callEventWithAttributeHandler("div", "bounce"), "no onbounce for div");
+ ok(!callEventWithAttributeHandler("div", "finish"), "no onfinish for div");
+ ok(!callEventWithAttributeHandler("div", "start"), "no onstart for div");
+
+ ok(callEventWithAttributeHandler("marquee", "bounce"), "onbounce for marquee");
+ ok(callEventWithAttributeHandler("marquee", "finish"), "onfinish for marquee");
+ ok(callEventWithAttributeHandler("marquee", "start"), "onstart for marquee");
+ </script>
+</body>
+</html>
diff --git a/dom/events/test/test_messageEvent.html b/dom/events/test/test_messageEvent.html
new file mode 100644
index 0000000000..ac12bbc99b
--- /dev/null
+++ b/dom/events/test/test_messageEvent.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=848294
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 848294</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <script type="application/javascript">
+ function testMessageEvent(e, test) {
+ ok(e, "MessageEvent created");
+ is(e.type, 'message', 'MessageEvent.type is right');
+
+ is(e.data, 'data' in test ? test.data : null, 'MessageEvent.data is ok');
+ is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok');
+ is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok');
+ is(e.source, 'source' in test ? test.source : null, 'MessageEvent.source is ok');
+
+ if (test.ports != undefined) {
+ is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok');
+ is(e.ports, e.ports, 'MessageEvent.ports is ok');
+ } else {
+ ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
+ }
+ }
+
+ function runTest() {
+ var channel = new MessageChannel();
+
+ var tests = [
+ {},
+ { data: 42 },
+ { data: {} },
+ { data: true, origin: 'wow' },
+ { data: [], lastEventId: 'wow2' },
+ { data: null, source: null },
+ { data: window, source: window },
+ { data: window, source: channel.port1 },
+ { data: window, source: channel.port1, ports: [ channel.port1, channel.port2 ] },
+ { data: null, ports: [] },
+ ];
+
+ while (tests.length) {
+ var test = tests.shift();
+
+ var e = new MessageEvent('message', test);
+ testMessageEvent(e, test);
+
+ e = new MessageEvent('message');
+ e.initMessageEvent('message', true, true,
+ 'data' in test ? test.data : null,
+ 'origin' in test ? test.origin : '',
+ 'lastEventId' in test ? test.lastEventId : '',
+ 'source' in test ? test.source : null,
+ 'ports' in test ? test.ports : []);
+ testMessageEvent(e, test);
+ }
+
+ try {
+ var e = new MessageEvent('foobar', { source: 42 });
+ ok(false, "Source has to be a window or a port");
+ } catch(ex) {
+ ok(true, "Source has to be a window or a port");
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ runTest();
+ </script>
+</body>
+</html>
diff --git a/dom/events/test/test_messageEvent_init.html b/dom/events/test/test_messageEvent_init.html
new file mode 100644
index 0000000000..9f5eea8f37
--- /dev/null
+++ b/dom/events/test/test_messageEvent_init.html
@@ -0,0 +1,25 @@
+<html><head>
+<title>Test for bug 1308956</title>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+
+<body>
+ <script>
+
+var a = new MessageEvent("message")
+ok(!!a, "We have a MessageEvent");
+is(a.ports.length, 0, "By default MessageEvent.ports is an empty array");
+
+a.initMessageEvent("message", true, false, {}, window.location.href, "", null, []);
+ok(Array.isArray(a.ports), "After InitMessageEvent() we have an array");
+is(a.ports.length, 0, "Length is 0");
+
+var mc = new MessageChannel();
+a.initMessageEvent("message", true, false, {}, window.location.href, "", null, [mc.port1]);
+ok(Array.isArray(a.ports), "After InitMessageEvent() we have an array");
+is(a.ports.length, 1, "Length is 1");
+
+ </script>
+</body>
+</html>
diff --git a/dom/events/test/test_mouse_capture_iframe.html b/dom/events/test/test_mouse_capture_iframe.html
new file mode 100644
index 0000000000..7f7a15ec95
--- /dev/null
+++ b/dom/events/test/test_mouse_capture_iframe.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test mouse capture for iframe</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/paint_listener.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<style>
+#target {
+ width: 150px;
+ height: 150px;
+}
+</style>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1680405">Mozilla Bug 1680405</a>
+<iframe id="target" frameborder="0" scrolling="no" src="http://example.com/tests/dom/events/test/file_empty.html"></iframe>
+<script>
+
+function waitForMessage(aEventType) {
+ return new Promise(function(aResolve, aReject) {
+ window.addEventListener("message", function listener(aEvent) {
+ is(aEvent.data, aEventType, `check received message ${aEvent.data}`);
+ aResolve();
+ }, { once: true });
+ });
+}
+
+let iframe = document.getElementById("target");
+
+add_task(async function init() {
+ await SimpleTest.promiseFocus();
+ await SpecialPowers.pushPrefEnv({ set: [["test.events.async.enabled", true]] });
+ disableNonTestMouseEvents(true);
+ SimpleTest.registerCleanupFunction(() => {
+ disableNonTestMouseEvents(false);
+ });
+
+ await SpecialPowers.spawn(iframe, [], () => {
+ let handler = function(e) {
+ content.parent.postMessage(e.type, "*");
+ };
+ content.document.addEventListener("mousedown", handler);
+ content.document.addEventListener("mousemove", handler);
+ content.document.addEventListener("mouseup", handler);
+ });
+
+ await waitUntilApzStable();
+});
+
+add_task(async function testMouseCaptureOnXoriginIframe() {
+ let unexpectedHandler = function(e) {
+ ok(false, `receive unexpected ${e.type} event`);
+ };
+ document.addEventListener("mousedown", unexpectedHandler);
+ document.addEventListener("mousemove", unexpectedHandler);
+ document.addEventListener("mouseup", unexpectedHandler);
+
+ synthesizeMouseAtCenter(iframe, { type: "mousedown" });
+ await waitForMessage("mousedown");
+
+ synthesizeMouse(iframe, 200, 200, { type: "mousemove" });
+ await waitForMessage("mousemove");
+
+ synthesizeMouse(iframe, 200, 200, { type: "mouseup" });
+ await waitForMessage("mouseup");
+});
+</script>
diff --git a/dom/events/test/test_mouse_enterleave_iframe.html b/dom/events/test/test_mouse_enterleave_iframe.html
new file mode 100644
index 0000000000..ee4b4f6fc1
--- /dev/null
+++ b/dom/events/test/test_mouse_enterleave_iframe.html
@@ -0,0 +1,272 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test mouseenter and mouseleave for iframe.</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<style>
+#start {
+ width: 300px;
+ height: 30px;
+}
+
+#target, #target2 {
+ width: 150px;
+ height: 150px;
+ background-color: #fcc;
+ display: inline-block;
+}
+
+#frame, #frame2 {
+ height: 100%;
+ width: 100%;
+}
+
+#reflow, #div {
+ width: 300px;
+ height: 10px;
+ background-color: lightgreen;
+}
+</style>
+<div id="start">Start from here!!</div>
+<div id="div"></div>
+<div id="target">
+ <iframe id="frame" frameborder="0" scrolling="no" src="http://example.com/tests/dom/events/test/file_mouse_enterleave.html"></iframe>
+</div>
+<div id="target2">
+ <iframe id="frame2" frameborder="0" scrolling="no" src="http://example.com/tests/dom/events/test/file_mouse_enterleave.html"></iframe>
+</div>
+<div id="reflow"></div>
+<script>
+
+function reflow() {
+ let div = document.getElementById("reflow");
+ div.style.display = "none";
+ div.getBoundingClientRect();
+ div.style.display = "block";
+ div.getBoundingClientRect();
+}
+
+function waitForMessage(aRemoteTarget, aEventType, aTargetName) {
+ return new Promise(function(aResolve, aReject) {
+ window.addEventListener("message", function listener(aEvent) {
+ if (aEvent.source != aRemoteTarget.contentWindow) {
+ return;
+ }
+
+ if (aEvent.data.eventType !== aEventType) {
+ window.removeEventListener("message", listener);
+ ok(false, `receive unexpected message ${JSON.stringify(aEvent.data)}`);
+ aReject(new Error(`receive unexpected message ${JSON.stringify(aEvent.data)}`));
+ return;
+ }
+
+ if (aEvent.data.targetName !== aTargetName) {
+ return;
+ }
+
+ ok(true, `receive message ${JSON.stringify(aEvent.data)}`);
+ // Trigger a reflow which will generate synthesized mouse move event.
+ aRemoteTarget.contentWindow.postMessage("reflow", "*");
+ // Now wait a bit to see if there is any unexpected message fired.
+ setTimeout(function() {
+ window.removeEventListener("message", listener);
+ aResolve();
+ }, 0);
+ });
+ });
+}
+
+function waitForLeaveEvent(aTarget) {
+ return new Promise(function(aResolve) {
+ aTarget.addEventListener("mouseleave", function(aEvent) {
+ ok(true, `receive ${aEvent.type}`);
+ aResolve();
+ }, { once: true });
+ });
+}
+
+function waitForEnterLeaveEvents(aEnterTarget, aLeaveTarget) {
+ let expectedEvents = [{target: aEnterTarget, eventName: "mouseenter"}];
+ if (aLeaveTarget) {
+ expectedEvents.push({target: aLeaveTarget, eventName: "mouseleave"})
+ }
+
+ return new Promise(function(aResolve, aReject) {
+ function cleanup() {
+ aEnterTarget.removeEventListener("mouseenter", listener);
+ aEnterTarget.removeEventListener("mouseleave", unexpectedEvent);
+ if (aLeaveTarget) {
+ aLeaveTarget.removeEventListener("mouseenter", unexpectedEvent);
+ aLeaveTarget.removeEventListener("mouseleave", listener);
+ }
+ }
+
+ function unexpectedEvent(aEvent) {
+ cleanup();
+ ok(false, `receive unexpected ${aEvent.type}`);
+ aReject(new Error(`receive unexpected ${aEvent.type}`));
+ }
+
+ async function listener(aEvent) {
+ if (expectedEvents.length <= 0) {
+ unexpectedEvent(aEvent);
+ return;
+ }
+
+ let expectedEvent = expectedEvents.pop();
+ if (expectedEvent.target == aEvent.target &&
+ expectedEvent.eventName == aEvent.type) {
+ ok(true, `receive ${aEvent.type}`);
+ } else {
+ unexpectedEvent(aEvent);
+ return;
+ }
+
+ if (expectedEvents.length == 0) {
+ // Trigger a reflow which will generate synthesized mouse move event.
+ reflow();
+ // Now wait a bit to see if there is any unexpected event fired.
+ setTimeout(function() {
+ cleanup();
+ aResolve();
+ }, 0);
+ }
+ }
+
+ aEnterTarget.addEventListener("mouseenter", listener);
+ aEnterTarget.addEventListener("mouseleave", unexpectedEvent);
+ if (aLeaveTarget) {
+ aLeaveTarget.addEventListener("mouseenter", unexpectedEvent);
+ aLeaveTarget.addEventListener("mouseleave", listener);
+ }
+ });
+}
+
+function moveMouseToInitialPosition() {
+ return new Promise((aResolve) => {
+ let start = document.getElementById("start");
+ let startRect = start.getBoundingClientRect();
+ info("Mouse moves to initial position");
+ synthesizeNativeMouseMove(start, startRect.width / 2, startRect.height / 2,
+ aResolve);
+ });
+}
+
+add_task(async function init() {
+ // Wait for focus before starting tests.
+ await SimpleTest.promiseFocus();
+
+ // Move mouse to initial position.
+ await moveMouseToInitialPosition();
+});
+
+add_task(async function testMouseEnterLeave() {
+ let div = document.getElementById("div");
+ let divRect = div.getBoundingClientRect();
+ let target = document.getElementById("target");
+ let targetRect = target.getBoundingClientRect();
+ let iframe = document.getElementById("frame");
+
+ info("Mouse moves to the div above iframe");
+ let promise = waitForEnterLeaveEvents(div);
+ synthesizeNativeMouseMove(div, divRect.width / 2, divRect.height / 2);
+ await promise;
+
+ info("Mouse moves into iframe");
+ promise = Promise.all([waitForEnterLeaveEvents(target, div),
+ waitForMessage(iframe, "mouseenter", "div"),
+ waitForMessage(iframe, "mouseenter", "html")]);
+ synthesizeNativeMouseMove(target, targetRect.width / 2, targetRect.height / 2);
+ await promise;
+
+ info("Mouse moves out from iframe to the div above iframe");
+ promise = Promise.all([waitForEnterLeaveEvents(div, target),
+ waitForMessage(iframe, "mouseleave", "div"),
+ waitForMessage(iframe, "mouseleave", "html")]);
+ synthesizeNativeMouseMove(div, divRect.width / 2, divRect.height / 2);
+ await promise;
+
+ // Move mouse back to initial position. This is to prevent unexpected
+ // mouseleave event in initial steps for test-verify which runs same test
+ // multiple times.
+ await moveMouseToInitialPosition();
+});
+
+add_task(async function testMouseEnterLeaveBetweenIframe() {
+ let target = document.getElementById("target");
+ let targetRect = target.getBoundingClientRect();
+ let iframe = document.getElementById("frame");
+
+ info("Mouse moves into the first iframe");
+ let promise = Promise.all([waitForEnterLeaveEvents(target),
+ waitForMessage(iframe, "mouseenter", "div"),
+ waitForMessage(iframe, "mouseenter", "html")]);
+ synthesizeNativeMouseMove(target, targetRect.width / 2, targetRect.height / 2);
+ await promise;
+
+ let target2 = document.getElementById("target2");
+ let target2Rect = target2.getBoundingClientRect();
+ let iframe2 = document.getElementById("frame2");
+
+ info("Mouse moves out from the first iframe to the second iframe");
+ promise = Promise.all([waitForEnterLeaveEvents(target2, target),
+ waitForMessage(iframe, "mouseleave", "div"),
+ waitForMessage(iframe, "mouseleave", "html"),
+ waitForMessage(iframe2, "mouseenter", "div"),
+ waitForMessage(iframe2, "mouseenter", "html")]);
+ synthesizeNativeMouseMove(target2, target2Rect.width / 2, target2Rect.height / 2);
+ await promise;
+
+ info("Mouse moves out from the second iframe to the first iframe");
+ promise = Promise.all([waitForEnterLeaveEvents(target, target2),
+ waitForMessage(iframe2, "mouseleave", "div"),
+ waitForMessage(iframe2, "mouseleave", "html"),
+ waitForMessage(iframe, "mouseenter", "div"),
+ waitForMessage(iframe, "mouseenter", "html")]);
+ synthesizeNativeMouseMove(target, targetRect.width / 2, targetRect.height / 2);
+ await promise;
+
+ // Move mouse back to initial position.
+ await Promise.all([waitForLeaveEvent(target),
+ waitForMessage(iframe, "mouseleave", "div"),
+ waitForMessage(iframe, "mouseleave", "html"),
+ moveMouseToInitialPosition()]);
+});
+
+add_task(async function testMouseEnterLeaveSwitchWindow() {
+ let target = document.getElementById("target");
+ let targetRect = target.getBoundingClientRect();
+ let iframe = document.getElementById("frame");
+
+ info("Mouse moves into iframe");
+ let promise = Promise.all([waitForEnterLeaveEvents(target),
+ waitForMessage(iframe, "mouseenter", "div"),
+ waitForMessage(iframe, "mouseenter", "html")]);
+ synthesizeNativeMouseMove(target, targetRect.width / 2, targetRect.height / 2);
+ await promise;
+
+ info("Open and switch to new window");
+ promise = Promise.all([waitForLeaveEvent(target),
+ waitForMessage(iframe, "mouseleave", "div"),
+ waitForMessage(iframe, "mouseleave", "html")]);
+ let win = window.open("http://example.com/tests/dom/events/test/file_mouse_enterleave.html");
+ // Trigger a reflow which will generate synthesized mouse move event.
+ win.postMessage("reflow", "*");
+ await promise;
+
+ info("Switch back to test window");
+ promise = Promise.all([waitForEnterLeaveEvents(target),
+ waitForMessage(iframe, "mouseenter", "div"),
+ waitForMessage(iframe, "mouseenter", "html")]);
+ win.close();
+ // Trigger a reflow which will generate synthesized mouse move event.
+ reflow();
+ synthesizeNativeMouseMove(target, targetRect.width / 2, targetRect.height / 2);
+ await promise;
+
+ // Move mouse back to initial position.
+ await Promise.all([waitForLeaveEvent(target),
+ moveMouseToInitialPosition()]);
+});
+</script>
diff --git a/dom/events/test/test_moz_mouse_pixel_scroll_event.html b/dom/events/test/test_moz_mouse_pixel_scroll_event.html
new file mode 100644
index 0000000000..d9b8be58d8
--- /dev/null
+++ b/dom/events/test/test_moz_mouse_pixel_scroll_event.html
@@ -0,0 +1,1363 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for MozMousePixelScroll events</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ .scrollable {
+ overflow: auto;
+ line-height: 1;
+ margin: 15px;
+ }
+ .scrollable > div {
+ width: 1000px;
+ height: 1000px;
+ font-size: 1000px;
+ line-height: 1;
+ }
+ </style>
+</head>
+<body>
+<p id="display"></p>
+<div id="Scrollable128" class="scrollable" style="font-size: 128px; width: 100px; height: 100px;">
+ <div>
+ <div id="Scrollable96" class="scrollable" style="font-size: 96px; width: 150px; height: 150px;">
+ <div>
+ <div id="Scrollable64" class="scrollable" style="font-size: 64px; width: 200px; height: 200px;">
+ <div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div id="Scrollable32" class="scrollable" style="font-size: 32px; width: 50px; height: 50px;">
+ <div>
+ </div>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(startTest, window);
+
+var gScrollable128 = document.getElementById("Scrollable128");
+var gScrollable96 = document.getElementById("Scrollable96");
+var gScrollable64 = document.getElementById("Scrollable64");
+var gScrollable32 = document.getElementById("Scrollable32");
+var gRoot = document.documentElement;
+
+function* prepareScrollUnits()
+{
+ var result = -1;
+ function handler(aEvent)
+ {
+ result = aEvent.detail;
+ aEvent.preventDefault();
+ setTimeout(runTest, 0);
+ }
+ window.addEventListener("MozMousePixelScroll", handler, { capture: true, passive: false });
+
+ yield waitForAllPaints(function () { setTimeout(runTest, 0); });
+
+ yield synthesizeWheel(gScrollable128, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable128.wheelLineHeight = result;
+ ok(result > 96 && result < 200, "prepareScrollUnits: gScrollable128.wheelLineHeight may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable96, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable96.wheelLineHeight = result;
+ ok(result > 64 && result < gScrollable128.wheelLineHeight, "prepareScrollUnits: gScrollable96.wheelLineHeight may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable64, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable64.wheelLineHeight = result;
+ ok(result > 32 && result < gScrollable96.wheelLineHeight, "prepareScrollUnits: gScrollable64.wheelLineHeight may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable32, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable32.wheelLineHeight = result;
+ ok(result > 16 && result < gScrollable64.wheelLineHeight, "prepareScrollUnits: gScrollable32.wheelLineHeight may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gRoot, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gRoot.wheelLineHeight = result;
+ ok(result > 10 && result < gScrollable32.wheelLineHeight, "prepareScrollUnits: gRoot.wheelLineHeight may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable128, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable128.wheelHorizontalLine = result;
+ ok(result > 50 && result < 200, "prepareScrollUnits: gScrollable128.wheelHorizontalLine may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable96, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable96.wheelHorizontalLine = result;
+ ok(result > 30 && result < gScrollable128.wheelHorizontalLine, "prepareScrollUnits: gScrollable96.wheelHorizontalLine may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable64, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable64.wheelHorizontalLine = result;
+ ok(result > 20 && result < gScrollable96.wheelHorizontalLine, "prepareScrollUnits: gScrollable64.wheelHorizontalLine may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable32, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable32.wheelHorizontalLine = result;
+ ok(result > 12 && result < gScrollable64.wheelHorizontalLine, "prepareScrollUnits: gScrollable32.wheelHorizontalLine may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gRoot, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gRoot.wheelHorizontalLine = result;
+ ok(result > 5 && result < gScrollable32.wheelHorizontalLine, "prepareScrollUnits: gRoot.wheelHorizontalLine may be illegal value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable128, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable128.wheelPageHeight = result;
+ ok(result >= (100 - gScrollable128.wheelLineHeight * 2) && result <= 100,
+ "prepareScrollUnits: gScrollable128.wheelLineHeight is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable96, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable96.wheelPageHeight = result;
+ ok(result >= (150 - gScrollable96.wheelLineHeight * 2) && result <= 150,
+ "prepareScrollUnits: gScrollable96.wheelLineHeight is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable64, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable64.wheelPageHeight = result;
+ ok(result >= (200 - gScrollable64.wheelLineHeight * 2) && result <= 200,
+ "prepareScrollUnits: gScrollable64.wheelLineHeight is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable32, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gScrollable32.wheelPageHeight = result;
+ ok(result >= (50 - gScrollable32.wheelLineHeight * 2) && result <= 50,
+ "prepareScrollUnits: gScrollable32.wheelLineHeight is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gRoot, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaY: 1.0, lineOrPageDeltaY: 1 });
+ gRoot.wheelPageHeight = result;
+ ok(window.innerHeight - result < 100 && window.innerHeight - result > 0,
+ "prepareScrollUnits: gRoot.wheelLineHeight is strange value, got " + result);
+
+
+ result = -1;
+ yield synthesizeWheel(gScrollable128, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable128.wheelPageWidth = result;
+ ok(result >= (100 - gScrollable128.wheelLineHeight * 2) && result <= 100,
+ "prepareScrollUnits: gScrollable128.wheelPageWidth is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable96, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable96.wheelPageWidth = result;
+ ok(result >= (150 - gScrollable96.wheelLineHeight * 2) && result <= 150,
+ "prepareScrollUnits: gScrollable96.wheelPageWidth is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable64, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable64.wheelPageWidth = result;
+ ok(result >= (200 - gScrollable64.wheelLineHeight * 2) && result <= 200,
+ "prepareScrollUnits: gScrollable64.wheelPageWidth is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gScrollable32, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gScrollable32.wheelPageWidth = result;
+ ok(result >= (50 - gScrollable32.wheelLineHeight * 2) && result <= 50,
+ "prepareScrollUnits: gScrollable32.wheelPageWidth is strange value, got " + result);
+
+ result = -1;
+ yield synthesizeWheel(gRoot, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, lineOrPageDeltaX: 1 });
+ gRoot.wheelPageWidth = result;
+ ok(window.innerWidth - result < 100 && window.innerWidth - result > 0,
+ "prepareScrollUnits: gRoot.wheelPageWidth is strange value, got " + result);
+
+ window.removeEventListener("MozMousePixelScroll", handler, true);
+}
+
+function* doTests()
+{
+ const kTests = [
+ // DOM_DELTA_LINE
+ { description: "Should be computed from nearest scrollable element, 128",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from root element if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: gRoot
+ }
+ },
+ { description: "Should be computed from root element, even if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: gRoot
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 128",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from root element if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gRoot
+ }
+ },
+ { description: "Should be computed from root element, even if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gRoot
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 128",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: null
+ }
+ },
+ { description: "Should be computed from root element if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: null
+ }
+ },
+ { description: "Should be computed from root element, even if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: null
+ }
+ },
+
+ // DOM_DELTA_PAGE
+ { description: "Should be computed from nearest scrollable element, 128",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from root element if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: gRoot
+ }
+ },
+ { description: "Should be computed from root element, even if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: -1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: gRoot
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 128",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable128
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable96
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gScrollable32
+ }
+ },
+ { description: "Should be computed from root element if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gRoot
+ }
+ },
+ { description: "Should be computed from root element, even if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: null, y: gRoot
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 128",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction",
+ target: gScrollable128,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable128.scrollLeft = 0;
+ gScrollable128.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable128, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 96",
+ target: gScrollable96,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable96, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable64, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element, even if not scrollable to the direction, 32",
+ target: gScrollable32,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable32.scrollLeft = 0;
+ gScrollable32.scrollTop = 0;
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gScrollable32, y: null
+ }
+ },
+ { description: "Should be computed from root element if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: null
+ }
+ },
+ { description: "Should be computed from root element, even if there is no scrollable element, root",
+ target: gRoot,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0, lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ prepare () {
+ },
+ cleanup () {
+ },
+ expected: {
+ x: gRoot, y: null
+ }
+ },
+
+ // Overflow: hidden; boxes shouldn't be ignored.
+ { description: "Should be computed from nearest scrollable element even if it hides overflow content, 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.style.overflow = "hidden";
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ gScrollable64.style.overflow = "auto";
+ },
+ expected: {
+ x: gScrollable64, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element even if it hides overflow content (X), 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.style.overflowX = "hidden";
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ gScrollable64.style.overflow = "auto";
+ },
+ expected: {
+ x: gScrollable64, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element even if it hides overflow content (Y), 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.style.overflowY = "hidden";
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ gScrollable64.style.overflow = "auto";
+ },
+ expected: {
+ x: gScrollable64, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element even if it hides overflow content (X), 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.style.overflowX = "hidden";
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ gScrollable64.style.overflow = "auto";
+ },
+ expected: {
+ x: null, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element even if it hides overflow content (Y), 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ prepare () {
+ gScrollable64.style.overflowY = "hidden";
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ gScrollable64.style.overflow = "auto";
+ },
+ expected: {
+ x: null, y: gScrollable64
+ }
+ },
+ { description: "Should be computed from nearest scrollable element even if it hides overflow content (X), 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable64.style.overflowX = "hidden";
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ gScrollable64.style.overflow = "auto";
+ },
+ expected: {
+ x: gScrollable64, y: null
+ }
+ },
+ { description: "Should be computed from nearest scrollable element even if it hides overflow content (Y), 64",
+ target: gScrollable64,
+ event: {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ prepare () {
+ gScrollable64.style.overflowY = "hidden";
+ gScrollable96.scrollLeft = 0;
+ gScrollable96.scrollTop = 0;
+ gScrollable64.scrollLeft = 0;
+ gScrollable64.scrollTop = 0;
+ },
+ cleanup () {
+ gScrollable64.style.overflow = "auto";
+ },
+ expected: {
+ x: gScrollable64, y: null
+ }
+ },
+ ];
+
+ var currentTest, description, firedX, firedY;
+ var expectedHandlerCalls;
+
+ function handler(aEvent)
+ {
+ aEvent.preventDefault();
+
+ if (aEvent.axis != MouseScrollEvent.HORIZONTAL_AXIS &&
+ aEvent.axis != MouseScrollEvent.VERTICAL_AXIS) {
+ ok(false,
+ description + "The event had invalid axis (" + aEvent.axis + ")");
+ if (--expectedHandlerCalls == 0) {
+ setTimeout(runTest, 0);
+ }
+ return;
+ }
+
+ var isHorizontal = (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS);
+ if ((isHorizontal && !currentTest.expected.x) ||
+ (!isHorizontal && !currentTest.expected.y)) {
+ ok(false,
+ description + "The event fired unexpectedly (" +
+ (isHorizontal ? "Horizontal" : "Vertical") + ")");
+ if (--expectedHandlerCalls == 0) {
+ setTimeout(runTest, 0);
+ }
+ return;
+ }
+
+ if (isHorizontal) {
+ firedX = true;
+ } else {
+ firedY = true;
+ }
+
+ var expectedDetail =
+ (currentTest.event.deltaMode == WheelEvent.DOM_DELTA_LINE) ?
+ (isHorizontal ? currentTest.expected.x.wheelHorizontalLine :
+ currentTest.expected.y.wheelLineHeight) :
+ (isHorizontal ? currentTest.expected.x.wheelPageWidth :
+ currentTest.expected.y.wheelPageHeight);
+ is(Math.abs(aEvent.detail), expectedDetail,
+ description + ((isHorizontal) ? "horizontal" : "vertical") + " event detail is wrong");
+
+ if (--expectedHandlerCalls == 0) {
+ setTimeout(runTest, 0);
+ }
+ }
+
+ window.addEventListener("MozMousePixelScroll", handler, { capture: true, passive: false });
+
+ for (var i = 0; i < kTests.length; i++) {
+ currentTest = kTests[i];
+ description = "doTests, " + currentTest.description + " (deltaMode: " +
+ (currentTest.event.deltaMode == WheelEvent.DOM_DELTA_LINE ?
+ "DOM_DELTA_LINE" : "DOM_DELTA_PAGE") +
+ ", deltaX: " + currentTest.event.deltaX +
+ ", deltaY: " + currentTest.event.deltaY + "): ";
+ currentTest.prepare();
+ firedX = firedY = false;
+ expectedHandlerCalls = (currentTest.expected.x ? 1 : 0)
+ + (currentTest.expected.y ? 1 : 0);
+ yield synthesizeWheel(currentTest.target, 10, 10, currentTest.event);
+ if (currentTest.expected.x) {
+ ok(firedX, description + "Horizontal MozMousePixelScroll event wasn't fired");
+ }
+ if (currentTest.expected.y) {
+ ok(firedY, description + "Vertical MozMousePixelScroll event wasn't fired");
+ }
+ currentTest.cleanup();
+ }
+
+ window.removeEventListener("MozMousePixelScroll", handler, true);
+}
+
+function* testBody()
+{
+ yield* prepareScrollUnits();
+ yield* doTests();
+}
+
+var gTestContinuation = null;
+
+function runTest()
+{
+ if (!gTestContinuation) {
+ gTestContinuation = testBody();
+ }
+ var ret = gTestContinuation.next();
+ if (ret.done) {
+ SimpleTest.finish();
+ }
+}
+
+function startTest() {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.delta_multiplier_x", 100],
+ ["mousewheel.default.delta_multiplier_y", 100],
+ ["mousewheel.default.delta_multiplier_z", 100],
+ ["mousewheel.with_alt.delta_multiplier_x", 100],
+ ["mousewheel.with_alt.delta_multiplier_y", 100],
+ ["mousewheel.with_alt.delta_multiplier_z", 100],
+ ["mousewheel.with_control.delta_multiplier_x", 100],
+ ["mousewheel.with_control.delta_multiplier_y", 100],
+ ["mousewheel.with_control.delta_multiplier_z", 100],
+ ["mousewheel.with_meta.delta_multiplier_x", 100],
+ ["mousewheel.with_meta.delta_multiplier_y", 100],
+ ["mousewheel.with_meta.delta_multiplier_z", 100],
+ ["mousewheel.with_shift.delta_multiplier_x", 100],
+ ["mousewheel.with_shift.delta_multiplier_y", 100],
+ ["mousewheel.with_shift.delta_multiplier_z", 100],
+ ["mousewheel.with_win.delta_multiplier_x", 100],
+ ["mousewheel.with_win.delta_multiplier_y", 100],
+ ["mousewheel.with_win.delta_multiplier_z", 100],
+ // If APZ is enabled we should ensure the preventDefault calls work even
+ // if the test is running slowly.
+ ["apz.content_response_timeout", 2000],
+ ]}, runTest);
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_offsetxy.html b/dom/events/test/test_offsetxy.html
new file mode 100644
index 0000000000..693683d1b0
--- /dev/null
+++ b/dom/events/test/test_offsetxy.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for DOM MouseEvent offsetX/Y</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="d" style="position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px"></div>
+<div id="d2" style="position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px; transform:translateX(100px)"></div>
+<div id="d3" style="display:none; position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px"></div>
+<div id="d4" style="transform:scale(0); position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px"></div>
+
+<pre id="test">
+<script type="application/javascript">
+
+var offsetX = -1, offsetY = -1;
+var ev = new MouseEvent("click", {clientX:110, clientY:110});
+is(ev.offsetX, 110);
+is(ev.offsetY, 110);
+is(ev.offsetX, ev.pageX);
+is(ev.offsetY, ev.pageY);
+d.addEventListener("click", function (event) {
+ is(ev, event, "Event objects must match");
+ offsetX = event.offsetX;
+ offsetY = event.offsetY;
+});
+d.dispatchEvent(ev);
+is(offsetX, 5);
+is(offsetY, 5);
+is(ev.offsetX, 5);
+is(ev.offsetY, 5);
+
+var ev2 = new MouseEvent("click", {clientX:220, clientY:130});
+is(ev2.offsetX, 220);
+is(ev2.offsetY, 130);
+is(ev2.offsetX, ev2.pageX);
+is(ev2.offsetY, ev2.pageY);
+d2.addEventListener("click", function (event) {
+ is(ev2, event, "Event objects must match");
+ offsetX = event.offsetX;
+ offsetY = event.offsetY;
+});
+d2.dispatchEvent(ev2);
+is(offsetX, 15);
+is(offsetY, 25);
+is(ev2.offsetX, 15);
+is(ev2.offsetY, 25);
+
+var ev3 = new MouseEvent("click", {clientX:110, clientY:110});
+is(ev3.offsetX, 110);
+is(ev3.offsetY, 110);
+is(ev3.offsetX, ev3.pageX);
+is(ev3.offsetY, ev3.pageY);
+d3.addEventListener("click", function (event) {
+ is(ev3, event, "Event objects must match");
+ offsetX = event.offsetX;
+ offsetY = event.offsetY;
+});
+d3.dispatchEvent(ev3);
+is(offsetX, 0);
+is(offsetY, 0);
+is(ev3.offsetX, 0);
+is(ev3.offsetY, 0);
+
+var ev4 = new MouseEvent("click", {clientX:110, clientY:110});
+is(ev4.offsetX, 110);
+is(ev4.offsetY, 110);
+is(ev4.offsetX, ev4.pageX);
+is(ev4.offsetY, ev4.pageY);
+d4.addEventListener("click", function (event) {
+ is(ev4, event, "Event objects must match");
+ offsetX = event.offsetX;
+ offsetY = event.offsetY;
+});
+d4.dispatchEvent(ev4);
+is(offsetX, 0);
+is(offsetY, 0);
+is(ev4.offsetX, 0);
+is(ev4.offsetY, 0);
+
+// Now redispatch ev4 to "d" to make sure that its offsetX gets updated
+// relative to the new target. Have to set "ev" to "ev4", because the listener
+// on "d" expects to see "ev" as the event.
+ev = ev4;
+d.dispatchEvent(ev4);
+is(offsetX, 5);
+is(offsetY, 5);
+is(ev.offsetX, 5);
+is(ev.offsetY, 5);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_onerror_handler_args.html b/dom/events/test/test_onerror_handler_args.html
new file mode 100644
index 0000000000..cf925736d8
--- /dev/null
+++ b/dom/events/test/test_onerror_handler_args.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1007790
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1007790</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1007790 **/
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(function() {
+ is(frames[0].onerror.toString(),
+ "function onerror(event, source, lineno, colno, error) {\n\n}",
+ "Should have the right arguments for onerror on window");
+ is($("content").onerror.toString(),
+ "function onerror(event) {\n\n}",
+ "Should have the right arguments for onerror on element");
+ SimpleTest.finish();
+ });
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1007790">Mozilla Bug 1007790</a>
+<p id="display"></p>
+<div id="content" style="display: none" onerror="">
+ <iframe srcdoc="<body onerror=''>"></iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_passive_listeners.html b/dom/events/test/test_passive_listeners.html
new file mode 100644
index 0000000000..dd132fc6bc
--- /dev/null
+++ b/dom/events/test/test_passive_listeners.html
@@ -0,0 +1,118 @@
+<html>
+<head>
+ <title>Tests for passive event listeners</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+<body>
+<p id="display"></p>
+<div id="dummy">
+</div>
+
+<script>
+var listenerHitCount;
+var doPreventDefault;
+
+function listener(e)
+{
+ listenerHitCount++;
+ if (doPreventDefault) {
+ // When this function is registered as a passive listener, this
+ // call should be a no-op and might report a console warning.
+ e.preventDefault();
+ }
+}
+
+function listener2(e)
+{
+ if (doPreventDefault) {
+ e.preventDefault();
+ }
+}
+
+var elem = document.getElementById('dummy');
+
+function doTest(description, passiveArg)
+{
+ listenerHitCount = 0;
+
+ elem.addEventListener('test', listener, { passive: passiveArg });
+
+ // Test with a cancelable event
+ var e1 = new Event('test', { cancelable: true });
+ elem.dispatchEvent(e1);
+ is(listenerHitCount, 1, description + ' | hit count');
+ var expectedDefaultPrevented = (doPreventDefault && !passiveArg);
+ is(e1.defaultPrevented, expectedDefaultPrevented, description + ' | default prevented');
+
+ // Test with a non-cancelable event
+ var e2 = new Event('test', { cancelable: false });
+ elem.dispatchEvent(e2);
+ is(listenerHitCount, 2, description + ' | hit count after non-cancelable event');
+ is(e2.defaultPrevented, false, description + ' | default prevented on non-cancelable event');
+
+ // Test combining passive-enabled and "traditional" listeners
+ elem.addEventListener('test', listener2);
+ var e3 = new Event('test', { cancelable: true });
+ elem.dispatchEvent(e3);
+ is(listenerHitCount, 3, description + ' | hit count with second listener');
+ is(e3.defaultPrevented, doPreventDefault, description + ' | default prevented with second listener');
+ elem.removeEventListener('test', listener2);
+
+ elem.removeEventListener('test', listener);
+}
+
+function testAddListenerKey(passiveListenerFirst)
+{
+ listenerHitCount = 0;
+ doPreventDefault = true;
+
+ elem.addEventListener('test', listener, { capture: false, passive: passiveListenerFirst });
+ // This second listener should not be registered, because the "key" of
+ // { type, callback, capture } is the same, even though the 'passive' flag
+ // is different.
+ elem.addEventListener('test', listener, { capture: false, passive: !passiveListenerFirst });
+
+ var e1 = new Event('test', { cancelable: true });
+ elem.dispatchEvent(e1);
+
+ is(listenerHitCount, 1, 'Duplicate addEventListener was correctly ignored');
+ is(e1.defaultPrevented, !passiveListenerFirst, 'Prevent-default result based on first registered listener');
+
+ // Even though passive is the opposite of the first addEventListener call, it
+ // should remove the listener registered above.
+ elem.removeEventListener('test', listener, { capture: false, passive: !passiveListenerFirst });
+
+ var e2 = new Event('test', { cancelable: true });
+ elem.dispatchEvent(e2);
+
+ is(listenerHitCount, 1, 'non-passive listener was correctly unregistered');
+ is(e2.defaultPrevented, false, 'no listener was registered to preventDefault this event');
+}
+
+function test()
+{
+ doPreventDefault = false;
+
+ doTest('base case', undefined);
+ doTest('non-passive listener', false);
+ doTest('passive listener', true);
+
+ doPreventDefault = true;
+
+ doTest('base case', undefined);
+ doTest('non-passive listener', false);
+ doTest('passive listener', true);
+
+ testAddListenerKey(false);
+ testAddListenerKey(true);
+}
+
+test();
+
+</script>
+
+</body>
+</html>
+
+
diff --git a/dom/events/test/test_paste_image.html b/dom/events/test/test_paste_image.html
new file mode 100644
index 0000000000..4643232865
--- /dev/null
+++ b/dom/events/test/test_paste_image.html
@@ -0,0 +1,192 @@
+<html><head>
+<title>Test for bug 891247</title>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+
+<script class="testbody" type="application/javascript">
+ function ImageTester() {
+ var counter = 0;
+ var images = [];
+ var that = this;
+
+ this.add = function(aFile) {
+ images.push(aFile);
+ };
+
+ this.test = function() {
+ for (var i = 0; i < images.length; i++) {
+ testImageSize(images[i]);
+ }
+ };
+
+ this.returned = function() {
+ counter++;
+ info("returned=" + counter + " images.length=" + images.length);
+ if (counter == images.length) {
+ info("test finish");
+ SimpleTest.finish();
+ }
+ };
+
+ function testImageSize(aFile) {
+ var source = window.URL.createObjectURL(aFile);
+ var image = new Image();
+ image.src = source;
+ var imageTester = that;
+ image.onload = function() {
+ is(this.width, 62, "Check generated image width");
+ is(this.height, 71, "Check generated image height");
+ if (aFile.type == "image/gif") {
+ // this test fails for image/jpeg and image/png because the images
+ // generated are slightly different
+ testImageCanvas(image);
+ }
+
+ imageTester.returned();
+ }
+
+ document.body.appendChild(image);
+ };
+
+ function testImageCanvas(aImage) {
+ var canvas = drawToCanvas(aImage);
+
+ var refImage = document.getElementById('image');
+ var refCanvas = drawToCanvas(refImage);
+
+ is(canvas.toDataURL(), refCanvas.toDataURL(), "Image should map pixel-by-pixel");
+ }
+
+ function drawToCanvas(aImage) {
+ var canvas = document.createElement("CANVAS");
+ document.body.appendChild(canvas);
+ canvas.width = aImage.width;
+ canvas.height = aImage.height;
+ canvas.getContext('2d').drawImage(aImage, 0, 0);
+ return canvas;
+ }
+ }
+
+ function copyImage(aImageId) {
+ // selection of the node
+ var node = document.getElementById(aImageId);
+ var docShell = SpecialPowers.wrap(window).docShell;
+
+ // let's copy the node
+ var documentViewer = docShell.contentViewer
+ .QueryInterface(SpecialPowers.Ci.nsIContentViewerEdit);
+ documentViewer.setCommandNode(node);
+ documentViewer.copyImage(documentViewer.COPY_IMAGE_ALL);
+ }
+
+ function doTest() {
+ SimpleTest.waitForExplicitFinish();
+
+ copyImage('image');
+
+ //--------- now check the content of the clipboard
+ var clipboard = SpecialPowers.Cc["@mozilla.org/widget/clipboard;1"]
+ .getService(SpecialPowers.Ci.nsIClipboard);
+ // does the clipboard contain text/unicode data ?
+ ok(clipboard.hasDataMatchingFlavors(["text/unicode"], clipboard.kGlobalClipboard),
+ "clipboard contains unicode text");
+ // does the clipboard contain text/html data ?
+ ok(clipboard.hasDataMatchingFlavors(["text/html"], clipboard.kGlobalClipboard),
+ "clipboard contains html text");
+ // does the clipboard contain image data ?
+ ok(clipboard.hasDataMatchingFlavors(["image/png"], clipboard.kGlobalClipboard),
+ "clipboard contains image");
+
+ window.addEventListener("paste", onPaste);
+
+ var textarea = SpecialPowers.wrap(document.getElementById('textarea'));
+ textarea.focus();
+ textarea.editor.paste(clipboard.kGlobalClipboard);
+ }
+
+ function onPaste(e) {
+ var imageTester = new ImageTester;
+ testFiles(e, imageTester);
+ testItems(e, imageTester);
+ imageTester.test();
+ }
+
+ function testItems(e, imageTester) {
+ var items = e.clipboardData.items;
+ is(items, e.clipboardData.items,
+ "Getting @items twice should return the same object");
+ var haveFiles = false;
+ ok(items instanceof DataTransferItemList, "@items implements DataTransferItemList");
+ ok(items.length > 0, "@items is not empty");
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ ok(item instanceof DataTransferItem, "each element of @items must implement DataTransferItem");
+ if (item.kind == "file") {
+ var file = item.getAsFile();
+ ok(file instanceof File, ".getAsFile() returns a File object");
+ ok(file.size > 0, "Files shouldn't have size 0");
+ imageTester.add(file);
+ }
+ }
+ }
+
+ function testFiles(e, imageTester) {
+ var files = e.clipboardData.files;
+
+ is(files, e.clipboardData.files,
+ "Getting the files array twice should return the same array");
+ ok(files.length > 0, "There should be at least one file in the clipboard");
+ for (var i = 0; i < files.length; i++) {
+ var file = files[i];
+ ok(file instanceof File, ".files should contain only File objects");
+ ok(file.size > 0, "This file shouldn't have size 0");
+ if (file.name == "image.png") {
+ is(file.type, "image/png", "This file should be a image/png");
+ } else if (file.name == "image.jpeg") {
+ is(file.type, "image/jpeg", "This file should be a image/jpeg");
+ } else if (file.name == "image.gif") {
+ is(file.type, "image/gif", "This file should be a image/gif");
+ } else {
+ info("file.name=" + file.name);
+ ok(false, "Unexpected file name");
+ }
+
+ testSlice(file);
+ imageTester.add(file);
+ // Adding the same image again so we can test concurrency
+ imageTester.add(file);
+ }
+ }
+
+ function testSlice(aFile) {
+ var blob = aFile.slice();
+ ok(blob instanceof Blob, ".slice returns a blob");
+ is(blob.size, aFile.size, "the blob has the same size");
+
+ blob = aFile.slice(123123);
+ is(blob.size, 0, ".slice overflow check");
+
+ blob = aFile.slice(123, 123141);
+ is(blob.size, aFile.size - 123, ".slice @size check");
+
+ blob = aFile.slice(123, 12);
+ is(blob.size, 0, ".slice @size check 2");
+
+ blob = aFile.slice(124, 134, "image/png");
+ is(blob.size, 10, ".slice @size check 3");
+ is(blob.type, "image/png", ".slice @type check");
+ }
+
+</script>
+<body onload="doTest();">
+ <img id="image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABHCA
+ IAAADQjmMaAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goUAwAgSAORBwAAABl0RVh0Q29
+ tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAABPSURBVGje7c4BDQAACAOga//OmuMbJGAurTbq
+ 6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6s31B0IqAY2/t
+ QVCAAAAAElFTkSuQmCC" />
+ <form>
+ <textarea id="textarea"></textarea>
+ </form>
+</body>
+</html>
diff --git a/dom/events/test/test_slotted_mouse_event.html b/dom/events/test/test_slotted_mouse_event.html
new file mode 100644
index 0000000000..9be751e95e
--- /dev/null
+++ b/dom/events/test/test_slotted_mouse_event.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Bug 1481500: mouse enter / leave events in slotted content</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+// We move the mouse from the #host to #target, then to #child-target.
+//
+// By the time we get to #child-target, we shouldn't have fired any mouseleave.
+function runTests() {
+ let iframe = document.createElement('iframe');
+ iframe.style.width = "600px";
+ iframe.style.height = "600px";
+ document.body.appendChild(iframe);
+ iframe.onload = () => frameLoaded(iframe);
+ iframe.srcdoc = `
+ <style>
+ #child-target {
+ width: 80px;
+ height: 80px;
+ background: yellow;
+ }
+ </style>
+ <div id="host"><div id="target"><div id="child-target"></div></div></div>
+ `;
+}
+
+function frameLoaded(iframe) {
+ let host = iframe.contentDocument.getElementById('host');
+ let target = iframe.contentDocument.getElementById('target');
+ let childTarget = iframe.contentDocument.getElementById('child-target');
+ let sawHost = false;
+ let sawTarget = false;
+ let finished = false;
+
+ host.attachShadow({ mode: 'open' }).innerHTML = `
+ <style>
+ :host {
+ width: 500px;
+ height: 500px;
+ background: purple;
+ }
+ ::slotted(div) {
+ width: 200px;
+ height: 200px;
+ background: green;
+ }
+ </style>
+ <slot></slot>
+ `;
+
+ host.addEventListener("mouseenter", e => {
+ if (finished)
+ return;
+ sawHost = true;
+ ok(true, "Should fire mouseenter on the host.");
+ });
+
+ host.addEventListener("mouseleave", e => {
+ if (finished)
+ return;
+ ok(false, "Should not fire mouseleave when moving the cursor to the slotted target");
+ });
+
+ target.addEventListener("mouseenter", () => {
+ if (finished)
+ return;
+ ok(sawHost, "Should've seen the hostmouseenter already");
+ sawTarget = true;
+ ok(true, "Moving the mouse into the target should trigger a mouseenter there");
+ });
+
+ target.addEventListener("mouseleave", () => {
+ if (finished)
+ return;
+ ok(false, "Should not fire mouseleave when moving the cursor to the slotted target's child");
+ });
+
+ childTarget.addEventListener("mouseenter", () => {
+ if (finished)
+ return;
+ ok(sawTarget, "Should've seen the target mouseenter already");
+ finished = true;
+ SimpleTest.finish();
+ });
+
+ synthesizeMouseAtCenter(host, { type: "mousemove" });
+ synthesizeMouseAtCenter(target, { type: "mousemove" });
+ synthesizeMouseAtCenter(childTarget, { type: "mousemove" });
+}
+
+SimpleTest.waitForExplicitFinish();
+window.onload = () => {
+ SimpleTest.waitForFocus(runTests);
+};
+</script>
diff --git a/dom/events/test/test_slotted_text_click.html b/dom/events/test/test_slotted_text_click.html
new file mode 100644
index 0000000000..34464bd918
--- /dev/null
+++ b/dom/events/test/test_slotted_text_click.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Bug 1481500: click / activation on text activates the slot it's assigned to</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+function generateLotsOfText() {
+ let text = "Some text. ";
+ for (let i = 0; i < 10; ++i)
+ text += text;
+ return text;
+}
+
+function runTests() {
+ let iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.onload = () => frameLoaded(iframe);
+ iframe.width = "350"
+ iframe.height = "350"
+ iframe.srcdoc =
+ `<div id="host">${generateLotsOfText()}</div>`
+}
+
+function frameLoaded(iframe) {
+ let host = iframe.contentDocument.getElementById('host');
+
+ host.attachShadow({ mode: 'open' }).innerHTML = `
+ <style>
+ :host {
+ width: 300px;
+ height: 300px;
+ overflow: hidden;
+ }
+ </style>
+ <slot></slot>
+ `;
+
+ let slot = host.shadowRoot.querySelector('slot');
+ let mousedownFired = false;
+ let mouseupFired = false;
+ slot.addEventListener('mousedown', function() {
+ ok(true, "Mousedown should fire on the slot when clicking on text");
+ mousedownFired = true;
+ });
+
+ slot.addEventListener('click', function() {
+ ok(true, "Click should target the slot");
+ ok(mousedownFired, "mousedown should've fired");
+ ok(mouseupFired, "click should've fired");
+ SimpleTest.finish();
+ });
+
+ slot.addEventListener('mouseup', function() {
+ // FIXME: When we fix bug 1481517, this check should move to the mousedown listener.
+ ok(this.matches(":active"), "Slot should become active");
+ mouseupFired = true;
+ });
+
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ synthesizeMouseAtPoint(150, 150, { type: "mousedown" });
+ synthesizeMouseAtPoint(150, 150, { type: "mouseup" });
+ });
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+window.onload = () => {
+ SimpleTest.waitForFocus(runTests);
+};
+</script>
diff --git a/dom/events/test/test_text_event_in_content.html b/dom/events/test/test_text_event_in_content.html
new file mode 100644
index 0000000000..916a20b61b
--- /dev/null
+++ b/dom/events/test/test_text_event_in_content.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<html>
+<head>
+ <title>Not dispatching DOM "text" event on web apps</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<input id="input">
+<textarea id="textarea"></textarea>
+<div contenteditable id="editor"><p><br></p></div>
+<script>
+SimpleTest.waitForExplicitFinish();
+SimpleTest.expectAssertions(2); // Assertions in WSRunScanner::TextFragmentData::GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace()
+SimpleTest.waitForFocus(function doTests() {
+ for (let editorId of ["input", "textarea", "editor"]) {
+ let editor = document.getElementById(editorId);
+ editor.focus();
+ let fired = false;
+ function onText() {
+ fired = true;
+ }
+ editor.addEventListener("text", onText);
+
+ fired = false;
+ synthesizeCompositionChange({
+ composition: {string: "abc",
+ clauses: [{length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE}]},
+ caret: {start: 3, length: 0},
+ });
+ ok(!fired, `Starting composition shouldn't fire DOM "text" event in ${editorId}`);
+ fired = false;
+ synthesizeComposition({type: "compositioncommitasis", key: {key: "KEY_Enter"}});
+ ok(!fired, `Committing composition with the latest string shouldn't fire DOM "text" event in ${editorId}`);
+
+ fired = false;
+ synthesizeCompositionChange({
+ composition: {string: "def",
+ clauses: [{length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE}]},
+ caret: {start: 3, length: 0},
+ });
+ ok(!fired, `Restarting composition shouldn't fire DOM "text" event in ${editorId}`);
+ fired = false;
+ synthesizeComposition({type: "compositioncommit", data: "", key: {key: "KEY_Escape"}});
+ ok(!fired, `Committing composition with empty string shouldn't fire DOM "text" event in ${editorId}`);
+
+ fired = false;
+ synthesizeCompositionChange({
+ composition: {string: "de",
+ clauses: [{length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE}]},
+ caret: {start: 2, length: 0},
+ });
+ ok(!fired, `Restarting composition shouldn't fire DOM "text" event in ${editorId}`);
+ fired = false;
+ synthesizeComposition({type: "compositioncommit", data: "def", key: {key: "KEY_Escape"}});
+ ok(!fired, `Committing composition with new string shouldn't fire DOM "text" event in ${editorId}`);
+
+ fired = false;
+ synthesizeComposition({type: "compositioncommit", data: "ghi"});
+ ok(!fired, `Inserting string shouldn't fire DOM "text" event in ${editorId}`);
+
+ editor.removeEventListener("text", onText);
+ }
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_unbound_before_in_active_chain.html b/dom/events/test/test_unbound_before_in_active_chain.html
new file mode 100644
index 0000000000..b62d44bb31
--- /dev/null
+++ b/dom/events/test/test_unbound_before_in_active_chain.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>Test for bug 1489139: Unbound generated content in the active chain</title>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<style>
+#target, #target::before {
+ width: 200px;
+ height: 200px;
+}
+
+#target::before {
+ content: " ";
+ display: block;
+ background: green;
+}
+
+#target:active::before {
+ content: "";
+ background: red;
+}
+</style>
+Should see a green square after clicking.
+<div id="target"></div>
+<script>
+SimpleTest.waitForExplicitFinish();
+onload = function() {
+ let target = document.getElementById("target");
+ requestAnimationFrame(() => {
+ synthesizeMouseAtPoint(100, 100, { type: "mousedown" })
+ ok(target.matches(":active"), "Should have been clicked");
+ requestAnimationFrame(() => {
+ synthesizeMouseAtPoint(100, 100, { type: "mouseup" })
+ ok(!target.matches(':active'), "Should stop matching :active afterwards");
+ SimpleTest.finish();
+ });
+ });
+}
+</script>
diff --git a/dom/events/test/test_use_conflated_keypress_event_model_on_newer_Office_Online_Server.html b/dom/events/test/test_use_conflated_keypress_event_model_on_newer_Office_Online_Server.html
new file mode 100644
index 0000000000..0a025d004d
--- /dev/null
+++ b/dom/events/test/test_use_conflated_keypress_event_model_on_newer_Office_Online_Server.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1545410
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Testing whether "keypress" event model is forcibly conflated model if the document is newer Office Online Server instance</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1545410">Bug 1545410</a>
+<p id="display"></p>
+<pre id="test"></pre>
+<input id="input">
+<iframe id="iframe" srcdoc='<html><body><div id="WACViewPanel_EditingElement" spellcheck="false" class="FireFox usehover WACEditing EditMode EditingSurfaceBody WACViewPanel_DisableLegacyKeyCodeAndCharCode" style="overflow: visible; visibility: visible;" contenteditable="true"></div></body></html>'></iframe>
+<script>
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async function doTests() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value", true],
+ ],
+ });
+
+ let iframe = document.getElementById("iframe");
+ iframe.contentDocument.body.firstChild.focus();
+ let keypressEvent;
+ iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("a", {}, iframe.contentWindow);
+ is(keypressEvent.keyCode, "a".charCodeAt(0),
+ "keyCode value of 'a' should be 'a'");
+ is(keypressEvent.charCode, "a".charCodeAt(0),
+ "charCode value of 'a' should be 'a'");
+
+ iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("KEY_Enter", {}, iframe.contentWindow);
+ is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+ "keyCode value of 'Enter' should be DOM_VK_RETURN");
+ is(keypressEvent.charCode, KeyboardEvent.DOM_VK_RETURN,
+ "charCode value of 'Enter' should be DOM_VK_RETURN");
+
+ let input = document.getElementById("input");
+ input.focus();
+ input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("a", {});
+ is(keypressEvent.keyCode, "a".charCodeAt(0),
+ "keyCode value of 'a' in the parent document should be 'a'");
+ is(keypressEvent.charCode, "a".charCodeAt(0),
+ "charCode value of 'a' in the parent document should be 'a'");
+
+ input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("KEY_Enter");
+ is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+ "keyCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+ is(keypressEvent.charCode, KeyboardEvent.DOM_VK_RETURN,
+ "charCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html b/dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html
new file mode 100644
index 0000000000..424f7ba700
--- /dev/null
+++ b/dom/events/test/test_use_split_keypress_event_model_on_old_Confluence.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1514940
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Testing whether "keypress" event model is forcibly split model if the document is old Confluence instance</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1514940">Bug 1514940</a>
+<p id="display"></p>
+<pre id="test"></pre>
+<input id="input">
+<iframe id="iframe" srcdoc="<html><body><p>Here is editor</p></body></html>"></iframe>
+<script>
+// Emulate window.tinyMCE.CursorTargetPlugin().getInfo() which is referred by
+// KeyPresEventModelCheckerChild.
+class CursorTargetPluginImpl {
+ getInfo() {
+ return {
+ longname: "Cursor Target plugin",
+ author: "Atlassian",
+ authorurl: "http://www.atlassian.com",
+ version: "1.0",
+ };
+ }
+}
+var tinyMCE = {
+ plugins: {
+ CursorTargetPlugin: CursorTargetPluginImpl,
+ },
+};
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async function doTests() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value", true],
+ ],
+ });
+
+ let iframe = document.getElementById("iframe");
+ let waitForCheckKeyPressEventModelEvent = new Promise(resolve => {
+ SpecialPowers.addSystemEventListener(iframe.contentDocument, "CheckKeyPressEventModel", resolve, {once: true});
+ });
+ iframe.contentDocument.body.setAttribute("contenteditable", "true");
+ await waitForCheckKeyPressEventModelEvent;
+ iframe.contentDocument.body.focus();
+ let keypressEvent;
+ iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("a", {}, iframe.contentWindow);
+ is(keypressEvent.keyCode, 0,
+ "keyCode value of 'a' should be 0");
+ is(keypressEvent.charCode, "a".charCodeAt(0),
+ "charCode value of 'a' should be 'a'");
+
+ iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("KEY_Enter", {}, iframe.contentWindow);
+ is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+ "keyCode value of 'Enter' should be DOM_VK_RETURN");
+ is(keypressEvent.charCode, 0,
+ "charCode value of 'Enter' should be 0");
+
+ let input = document.getElementById("input");
+ input.focus();
+ input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("a", {});
+ is(keypressEvent.keyCode, "a".charCodeAt(0),
+ "keyCode value of 'a' in the parent document should be 'a'");
+ is(keypressEvent.charCode, "a".charCodeAt(0),
+ "charCode value of 'a' in the parent document should be 'a'");
+
+ input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("KEY_Enter");
+ is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+ "keyCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+ is(keypressEvent.charCode, KeyboardEvent.DOM_VK_RETURN,
+ "charCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html b/dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html
new file mode 100644
index 0000000000..5e7445a065
--- /dev/null
+++ b/dom/events/test/test_use_split_keypress_event_model_on_old_Office_Online_Server.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1545410
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Testing whether "keypress" event model is forcibly split model if the document is old Office Online Server instance</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1545410">Bug 1545410</a>
+<p id="display"></p>
+<pre id="test"></pre>
+<input id="input">
+<iframe id="iframe" onload="srcdocLoaded()" srcdoc='<html><body><div id="WACViewPanel_EditingElement" spellcheck="false" class="FireFox usehover WACEditing EditMode EditingSurfaceBody" style="overflow: visible; visibility: visible;"></div></body></html>'></iframe>
+<script>
+SimpleTest.waitForExplicitFinish();
+let waitForCheckKeyPressEventModelEvent;
+function srcdocLoaded() {
+ waitForCheckKeyPressEventModelEvent = new Promise(resolve => {
+ dump(document.querySelector("iframe").contentDocument.location + "\n");
+ var doc = document.querySelector("iframe").contentDocument;
+ SpecialPowers.addSystemEventListener(doc, "CheckKeyPressEventModel", resolve, {once: true});
+ doc.getElementById("WACViewPanel_EditingElement").contentEditable = "true";
+ });
+}
+SimpleTest.waitForFocus(async function doTests() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value", true],
+ ],
+ });
+
+ let iframe = document.getElementById("iframe");
+ await waitForCheckKeyPressEventModelEvent;
+ iframe.contentDocument.body.firstChild.focus();
+ let keypressEvent;
+ iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("a", {}, iframe.contentWindow);
+ is(keypressEvent.keyCode, 0,
+ "keyCode value of 'a' should be 0");
+ is(keypressEvent.charCode, "a".charCodeAt(0),
+ "charCode value of 'a' should be 'a'");
+
+ iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("KEY_Enter", {}, iframe.contentWindow);
+ is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+ "keyCode value of 'Enter' should be DOM_VK_RETURN");
+ is(keypressEvent.charCode, 0,
+ "charCode value of 'Enter' should be 0");
+
+ let input = document.getElementById("input");
+ input.focus();
+ input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("a", {});
+ is(keypressEvent.keyCode, "a".charCodeAt(0),
+ "keyCode value of 'a' in the parent document should be 'a'");
+ is(keypressEvent.charCode, "a".charCodeAt(0),
+ "charCode value of 'a' in the parent document should be 'a'");
+
+ input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+ synthesizeKey("KEY_Enter");
+ is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+ "keyCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+ is(keypressEvent.charCode, KeyboardEvent.DOM_VK_RETURN,
+ "charCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/events/test/test_wheel_default_action.html b/dom/events/test/test_wheel_default_action.html
new file mode 100644
index 0000000000..2ddfb7d345
--- /dev/null
+++ b/dom/events/test/test_wheel_default_action.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for default action of WheelEvent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+SpecialPowers.pushPrefEnv({"set": [
+ ["mousewheel.system_scroll_override_on_root_content.enabled", false]
+]}, runTest);
+
+var subWin = null;
+
+function runTest() {
+ subWin = window.open("window_wheel_default_action.html", "_blank",
+ "width=500,height=500,scrollbars=yes");
+}
+
+function finish()
+{
+ subWin.close();
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/test_wheel_zoom_on_form_controls.html b/dom/events/test/test_wheel_zoom_on_form_controls.html
new file mode 100644
index 0000000000..69d498aed3
--- /dev/null
+++ b/dom/events/test/test_wheel_zoom_on_form_controls.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Zoom using wheel should work on form controls</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<button id="button" style="width:10px;height:10px;"></button><br>
+<input id="input" style="border: 10px solid green;"><br>
+<textarea id="textarea" style="border: 10px solid green;"></textarea><br>
+<select id="select"><option></option></select>
+<select id="list" size=4>
+ <option>XXXXXXXXXX</option>
+ <option>XXXXXXXXXX</option>
+ <option>XXXXXXXXXX</option>
+ <option>XXXXXXXXXX</option>
+ <option>XXXXXXXXXX</option>
+ <option>XXXXXXXXXX</option>
+</select>
+<script>
+
+ async function testControl(id) {
+ var initialZoom = SpecialPowers.getFullZoom(window);
+ var element = document.getElementById(id);
+
+ const zoomHasHappened = SimpleTest.promiseWaitForCondition(() => {
+ const zoom = SpecialPowers.getFullZoom(window);
+ return (zoom != initialZoom);
+ }, id + ": wheel event changed the zoom.");
+
+ let event = {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaY: 3,
+ ctrlKey: true
+ };
+ synthesizeWheel(element, 5, 5, event);
+
+ await zoomHasHappened;
+ isnot(SpecialPowers.getFullZoom(window), initialZoom, id + ": should have zoomed");
+ SpecialPowers.setFullZoom(window, initialZoom);
+ }
+
+ async function test() {
+ await testControl("button");
+ await testControl("input");
+ await testControl("textarea");
+ await testControl("select");
+ await testControl("list");
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(test);
+</script>
+</body>
+</html>
diff --git a/dom/events/test/window_bug1369072.html b/dom/events/test/window_bug1369072.html
new file mode 100644
index 0000000000..2ad1ade29d
--- /dev/null
+++ b/dom/events/test/window_bug1369072.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1369072
+-->
+<head>
+ <title>Test for Bug 1369072</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1369072">Mozilla Bug 1369072</a>
+<div id="display">
+<iframe id="iframe" srcdoc="<a id='anchor' href='about:home'>anchor text</a><div id='div'></div>" style="width: 300px; height: 300px;"></iframe>
+<!-- make <body> contents overflow -->
+<div style="width: 1000px; height: 1000px;"></div>
+</div>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests, window);
+
+function ok()
+{
+ window.opener.ok.apply(window.opener, arguments);
+}
+
+function is()
+{
+ window.opener.is.apply(window.opener, arguments);
+}
+
+async function runTests()
+{
+ var iframe = document.getElementById("iframe");
+ var anchor = iframe.contentDocument.getElementById("anchor");
+ var div = iframe.contentDocument.getElementById("div");
+
+ function resetScroll()
+ {
+ return new Promise(resolve => {
+ var scrollParent = document.documentElement.scrollTop || document.documentElement.scrollLeft;
+ var scrollChild = iframe.contentDocument.documentElement.scrollTop || iframe.contentDocument.documentElement.scrollLeft;
+ if (scrollParent) {
+ window.addEventListener("scroll", () => {
+ scrollParent = false;
+ if (!scrollChild) {
+ SimpleTest.executeSoon(resolve);
+ }
+ }, { once: true });
+ }
+ if (scrollChild) {
+ iframe.contentWindow.addEventListener("scroll", () => {
+ scrollChild = false;
+ if (!scrollParent) {
+ SimpleTest.executeSoon(resolve);
+ }
+ }, { once: true });
+ }
+ document.documentElement.scrollTop = 0;
+ document.documentElement.scrollLeft = 0;
+ iframe.contentDocument.documentElement.scrollTop = 0;
+ iframe.contentDocument.documentElement.scrollLeft = 0;
+ if (!scrollParent && !scrollChild) {
+ SimpleTest.executeSoon(resolve);
+ }
+ });
+ }
+
+ async function tryToScrollWithKey(aVertical)
+ {
+ await resetScroll();
+
+ return new Promise(resolve => {
+ // Wait scroll event
+ function onScroll() {
+ SimpleTest.executeSoon(resolve);
+ }
+ window.addEventListener("scroll", onScroll, { once: true });
+ iframe.contentWindow.addEventListener("scroll", onScroll, { once: true });
+
+ if (aVertical) {
+ synthesizeKey("KEY_ArrowDown");
+ } else {
+ synthesizeKey("KEY_ArrowRight");
+ }
+ });
+ }
+
+ // When iframe element has focus and the iframe document isn't scrollable, the parent document should be scrolled instead.
+ document.body.focus();
+ iframe.focus();
+ await tryToScrollWithKey(true);
+ ok(document.documentElement.scrollTop > 0, "ArrowDown keydown event at the iframe whose content is not scrollable should cause scrolling the parent document");
+ await tryToScrollWithKey(false);
+ ok(document.documentElement.scrollLeft > 0, "ArrowRight keydown event at the iframe whose content is not scrollable should cause scrolling the parent document");
+ await resetScroll();
+
+ // When iframe element has focus and the iframe document scrollable, the parent document shouldn't be scrolled.
+ document.body.focus();
+ div.style.height = "1000px";
+ div.style.width = "1000px";
+ iframe.focus();
+ await tryToScrollWithKey(true);
+ is(document.documentElement.scrollTop, 0, "ArrowDown keydown event at the iframe whose content is scrollable shouldn't cause scrolling the parent document");
+ ok(iframe.contentDocument.documentElement.scrollTop > 0, "ArrowDown keydown event at the iframe whose content is scrollable should cause scrolling the iframe document");
+ await tryToScrollWithKey(false);
+ is(document.documentElement.scrollLeft, 0, "ArrowRight keydown event at the iframe whose content is scrollable shouldn't cause scrolling the parent document");
+ ok(iframe.contentDocument.documentElement.scrollLeft > 0, "ArrowRight keydown event at the iframe whose content is scrollable should cause scrolling the iframe document");
+ await resetScroll();
+
+ // If iframe document cannot scroll to specific direction, parent document should be scrolled instead.
+ div.style.height = "1px";
+ div.style.width = "1000px";
+ iframe.focus();
+ await tryToScrollWithKey(true);
+ ok(document.documentElement.scrollTop > 0, "ArrowDown keydown event at the iframe whose content is scrollable only horizontally should cause scrolling the parent document");
+ await tryToScrollWithKey(false);
+ is(document.documentElement.scrollLeft, 0, "ArrowRight keydown event at the iframe whose content is scrollable only horizontally shouldn't cause scrolling the parent document");
+ ok(iframe.contentDocument.documentElement.scrollLeft > 0, "ArrowRight keydown event at the iframe whose content is scrollable only horizontally should cause scrolling the iframe document");
+ await resetScroll();
+
+ div.style.height = "1000px";
+ div.style.width = "1px";
+ iframe.focus();
+ await tryToScrollWithKey(true);
+ is(document.documentElement.scrollTop, 0, "ArrowDown keydown event at the iframe whose content is scrollable only vertically shouldn't cause scrolling the parent document");
+ ok(iframe.contentDocument.documentElement.scrollTop > 0, "ArrowDown keydown event at the iframe whose content is scrollable only vertically should cause scrolling the iframe document");
+ await tryToScrollWithKey(false);
+ ok(document.documentElement.scrollLeft > 0, "ArrowRight keydown event at the iframe whose content is scrollable only vertically should cause scrolling the parent document");
+ await resetScroll();
+
+ // Hidden iframe shouldn't consume keyboard events if it was not scrollable.
+ document.body.focus();
+ anchor.focus();
+ iframe.style.display = "none";
+ await tryToScrollWithKey(true);
+ ok(document.documentElement.scrollTop > 0, "ArrowDown keydown event after hiding the iframe should cause scrolling the parent document");
+ await tryToScrollWithKey(false);
+ ok(document.documentElement.scrollLeft > 0, "ArrowRight keydown event after hiding the iframe should cause scrolling the parent document");
+ await resetScroll();
+
+ // Make sure the result visible in the viewport.
+ document.documentElement.scrollTop = 0;
+ document.documentElement.scrollLeft = 0;
+ window.opener.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/events/test/window_bug1412775.xhtml b/dom/events/test/window_bug1412775.xhtml
new file mode 100644
index 0000000000..e1274c7bb5
--- /dev/null
+++ b/dom/events/test/window_bug1412775.xhtml
@@ -0,0 +1,8 @@
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="640" height="480">
+
+ <browser id="browser" type="content" primary="true" flex="1" src="about:blank"/>
+
+</window>
diff --git a/dom/events/test/window_bug1429572.html b/dom/events/test/window_bug1429572.html
new file mode 100644
index 0000000000..08c341df13
--- /dev/null
+++ b/dom/events/test/window_bug1429572.html
@@ -0,0 +1,345 @@
+<html>
+ <head>
+ <title></title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script>
+ var tests = [
+ simpleNonShadowTest,
+ nonShadowInputDate,
+ jsDispatchedNonShadowTouchEvents,
+ shadowDOMTest1,
+ shadowDOMTest2,
+ shadowDOMTest3,
+ jsDispatchedShadowTouchEvents,
+ jsDispatchedShadowTouchEvents2
+ ];
+ var host;
+ var host2;
+ var shadowRoot;
+ var shadowRoot2;
+ var winUtils;
+
+ var touchCounter = 0;
+ function createTouchArray(targetList) {
+ var touchArray = [];
+ for (var i = 0; i < targetList.length; ++i) {
+ touchArray.push(new Touch({identifier: ++touchCounter, target: targetList[i]}));
+ }
+ return touchArray;
+ }
+
+ function synthesizeTouches(targets, xOffsets) {
+ if (xOffsets) {
+ opener.is(targets.length, xOffsets.length, "Wrong xOffsets length!");
+ }
+ var touches = [];
+ var xs = [];
+ var ys = [];
+ var rxs = [];
+ var rys = [];
+ var angles = [];
+ var forces = [];
+ for (var i = 0; i < targets.length; ++i) {
+ touches.push(++touchCounter);
+ var rect = targets[i].getBoundingClientRect();
+ if (xOffsets) {
+ xs.push(rect.left + (rect.width / 2) + xOffsets[i]);
+ } else {
+ xs.push(rect.left + (rect.width / 2));
+ }
+ ys.push(rect.top + (rect.height / 2));
+ rxs.push(1);
+ rys.push(1);
+ angles.push(0);
+ forces.push(1);
+ }
+ winUtils.sendTouchEvent("touchstart",
+ touches, xs, ys, rxs, rys, angles, forces, 0);
+ winUtils.sendTouchEvent("touchend",
+ touches, xs, ys, rxs, rys, angles, forces, 0);
+ }
+
+ function next() {
+ if (!tests.length) {
+ opener.done();
+ window.close();
+ } else {
+ var test = tests.shift();
+ requestAnimationFrame(function() { setTimeout(test); });
+ }
+ }
+
+ function simpleNonShadowTest() {
+ var s1 = document.getElementById("span1");
+ var s2 = document.getElementById("span2");
+ var s3 = document.getElementById("span3");
+ var nonShadow = document.getElementById("nonshadow");
+ var event;
+ nonShadow.ontouchstart = function(e) {
+ event = e;
+ opener.is(e.targetTouches.length, 1, "Should have only one entry in targetTouches.");
+ opener.is(e.targetTouches[0].target, e.target, "targetTouches should contain event.target.");
+ opener.is(e.touches.length, 3, "touches list should contain all the touch objects.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain all the touch objects.");
+ }
+ synthesizeTouches([s1, s2, s3]);
+
+ opener.is(event.targetTouches.length, 1, "Should have only one entry in targetTouches. (2)");
+ opener.is(event.targetTouches[0].target, event.target, "targetTouches should contain event.target. (2)");
+ opener.is(event.touches.length, 3, "touches list should contain all the touch objects. (2)");
+ opener.is(event.changedTouches.length, 3, "changedTouches list should contain all the touch objects. (2)");
+
+ next();
+ }
+
+ function jsDispatchedNonShadowTouchEvents() {
+ var s1 = document.getElementById("span1");
+ var s2 = document.getElementById("span2");
+ var s3 = document.getElementById("span3");
+ var nonShadow = document.getElementById("nonshadow");
+ var didCallListener = false;
+ nonShadow.ontouchstart = function(e) {
+ didCallListener = true;
+ opener.is(e.targetTouches.length, 3, "Should have all the entries in targetTouches.");
+ opener.is(e.targetTouches[0].target, s1, "targetTouches should contain s1 element.");
+ opener.is(e.touches.length, 3, "touches list should contain all the touch objects.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain all the touch objects.");
+ }
+ var touchArray = createTouchArray([s1, s2, s3]);
+ var touchEvent = new TouchEvent("touchstart",
+ {
+ touches: touchArray,
+ targetTouches: touchArray,
+ changedTouches: touchArray
+ });
+ opener.is(touchEvent.targetTouches.length, 3, "Should have 3 entries in targetTouches");
+ nonShadow.dispatchEvent(touchEvent);
+ opener.ok(didCallListener, "Should have called the listener.");
+ opener.is(touchEvent.targetTouches.length, 3, "Should have all the entries in targetTouches. (2)");
+ opener.is(touchEvent.targetTouches[0].target, s1, "targetTouches should contain s1 element. (2)");
+ opener.is(touchEvent.touches.length, 3, "touches list should contain all the touch objects. (2)");
+ opener.is(touchEvent.changedTouches.length, 3, "changedTouches list should contain all the touch objects. (2)");
+
+ nonShadow.ontouchstart = null;
+ next();
+ }
+
+ function nonShadowInputDate() {
+ // This is a test for dispathing several touches to an element with
+ // native anonymous content.
+ var s1 = document.getElementById("span1");
+ var date = document.getElementById("date");
+ var nonShadow = document.getElementById("nonshadow");
+ var hasDateAsTarget = false;
+ var didCallListener = false;
+ nonShadow.ontouchstart = function(e) {
+ didCallListener = true;
+ if (e.targetTouches[0].target == date) {
+ hasDateAsTarget = true;
+ opener.is(e.targetTouches.length, 2, "Should have two entries in targetTouches.");
+ opener.is(e.targetTouches[0].target, e.target, "targetTouches should contain date.");
+ opener.is(e.targetTouches[1].target, e.target, "targetTouches should contain date twice.");
+ }
+ opener.is(e.touches.length, 3, "touches list should contain all the touch objects.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain all the touch objects.");
+ }
+
+ var rect = date.getBoundingClientRect();
+ var quarter = rect.width / 4;
+ synthesizeTouches([date, date, s1], [-quarter, quarter, 0]);
+ opener.ok(didCallListener, "Should have called listener.");
+ opener.ok(hasDateAsTarget, "Should have seen touchstart with date element as the target.")
+ nonShadow.ontouchstart = null;
+ next();
+ }
+
+ function shadowDOMTest1() {
+ var shadowS1 = shadowRoot.getElementById("shadowSpan1");
+
+ // Ensure retargeting works.
+ var hostHandled = false;
+ host.ontouchstart = function(e) {
+ hostHandled = true;
+ opener.is(e.targetTouches.length, 1, "Should have only one entry in targetTouches.");
+ opener.is(e.targetTouches[0].target, e.target, "targetTouches should contain event.target.");
+ opener.is(e.target, host, "Event and touch should have been retargeted.");
+ opener.is(e.touches.length, 1, "touches list should contain one touch object.");
+ opener.is(e.changedTouches.length, 1, "changedTouches list should contain one touch objects.");
+ }
+
+ // Ensure retargeting doesn't happen inside shadow DOM.
+ var shadowHandled = false;
+ shadowS1.ontouchstart = function(e) {
+ shadowHandled = true;
+ opener.is(e.targetTouches.length, 1, "Should have only one entry in targetTouches.");
+ opener.is(e.targetTouches[0].target, e.target, "targetTouches should contain event.target.");
+ opener.is(e.target, shadowS1, "Event and touch should not have been retargeted.");
+ opener.is(e.touches.length, 1, "touches list should contain one touch object.");
+ opener.is(e.changedTouches.length, 1, "changedTouches list should contain one touch objects.");
+ }
+ synthesizeTouches([shadowS1]);
+ opener.ok(hostHandled, "Should have called listener on host.");
+ opener.ok(shadowHandled, "Should have called listener on shadow DOM element.");
+ host.ontouchstart = null;
+ shadowS1.ontouchstart = null;
+
+ next();
+ }
+
+ function shadowDOMTest2() {
+ var shadowS1 = shadowRoot.getElementById("shadowSpan1");
+ var shadowS2 = shadowRoot.getElementById("shadowSpan2");
+ var s1 = document.getElementById("span1");
+
+ var hostHandled = false;
+ host.ontouchstart = function(e) {
+ opener.is(e.target, host, "Event.target should be the host element.");
+ hostHandled = true;
+ opener.is(e.targetTouches.length, 2, "Should have two entries in targetTouches.");
+ opener.is(e.targetTouches[0].target, e.target, "targetTouches should contain event.target.");
+ opener.is(e.targetTouches[1].target, e.target, "targetTouches should contain event.target twice.");
+ opener.is(e.touches.length, 3, "touches list should contain one touch object.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain one touch objects.");
+ }
+
+ synthesizeTouches([shadowS1, shadowS2, s1]);
+ opener.ok(hostHandled, "Should have called listener on host.");
+ host.ontouchstart = null;
+
+ next();
+ }
+
+
+ function shadowDOMTest3() {
+ var shadowS1 = shadowRoot.getElementById("shadowSpan1");
+ var shadowS2 = shadowRoot2.getElementById("shadowSpan2");
+ var s1 = document.getElementById("span1");
+
+ var hostHandled = false;
+ host.ontouchstart = function(e) {
+ opener.is(e.target, host, "Event.target should be the host element.");
+ hostHandled = true;
+ opener.is(e.targetTouches.length, 1, "Should have one entry in targetTouches.");
+ opener.is(e.targetTouches[0].target, e.target, "targetTouches should contain event.target.");
+ opener.is(e.touches.length, 3, "touches list should contain one touch object.");
+ opener.is(e.touches[0].target, host, "Should have retargeted the first Touch object.");
+ opener.is(e.touches[1].target, host2, "Should have retargeted the second Touch object.");
+ opener.is(e.touches[3].target, s1, "Touch object targeted to light DOM should keep its target as is.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain one touch objects.");
+ }
+
+ synthesizeTouches([shadowS1, shadowS2, s1]);
+ opener.ok(hostHandled, "Should have called listener on host.");
+ host.ontouchstart = null;
+
+ next();
+ }
+
+ function jsDispatchedShadowTouchEvents() {
+ var s1 = document.getElementById("span1");
+ var shadowS1 = shadowRoot.getElementById("shadowSpan1");
+ var shadowS2 = shadowRoot.getElementById("shadowSpan2");
+ var hostHandled = false;
+ var shadowHandled = false;
+ host.ontouchstart = function(e) {
+ hostHandled = true;
+ opener.is(e.targetTouches.length, 2, "Should have all the shadow entries in targetTouches.");
+ opener.is(e.targetTouches[0].target, host, "targetTouches shouldn't reveal shadow DOM.");
+ opener.is(e.targetTouches[1].target, host, "targetTouches shouldn't reveal shadow DOM.");
+ opener.is(e.touches.length, 3, "touches list should contain all the touch objects.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain all the touch objects.");
+ }
+ shadowS1.ontouchstart = function(e) {
+ shadowHandled = true;
+ opener.is(e.targetTouches.length, 3, "Should have all the in targetTouches.");
+ opener.is(e.targetTouches[0].target, shadowS1, "targetTouches should contain two shadow elements.");
+ opener.is(e.targetTouches[1].target, shadowS2, "targetTouches should contain two shadow elements.");
+ opener.is(e.targetTouches[2].target, s1, "targetTouches should contain a slight element.");
+ opener.is(e.touches.length, 3, "touches list should contain all the touch objects.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain all the touch objects.");
+ }
+ var touchArray = createTouchArray([shadowS1, shadowS2, s1]);
+ var touchEvent = new TouchEvent("touchstart",
+ {
+ composed: true,
+ touches: touchArray,
+ targetTouches: touchArray,
+ changedTouches: touchArray
+ });
+ opener.is(touchEvent.targetTouches.length, 3, "Should have 3 entries in targetTouches");
+ shadowS1.dispatchEvent(touchEvent);
+ opener.ok(hostHandled, "Should have called listener on host.");
+ opener.ok(shadowHandled, "Should have called listener on shadow DOM element.");
+ host.ontouchstart = null;
+ shadowS1.ontouchstart = null;
+ next();
+ }
+
+ function jsDispatchedShadowTouchEvents2() {
+ var s1 = document.getElementById("span1");
+ var shadowS1 = shadowRoot.getElementById("shadowSpan1");
+ var shadowS2 = shadowRoot2.getElementById("shadowSpan2");
+ var hostHandled = false;
+ var shadowHandled = false;
+ host.ontouchstart = function(e) {
+ hostHandled = true;
+ opener.is(e.targetTouches.length, 1, "Should have one shadow entry in targetTouches.");
+ opener.is(e.targetTouches[0].target, host, "targetTouches shouldn't reveal shadow DOM.");
+ opener.is(e.touches.length, 3, "touches list should contain all the touch objects.");
+ opener.is(e.touches[0].target, host, "Should have retargeted the first Touch object.");
+ opener.is(e.touches[1].target, host2, "Should have retargeted the second Touch object.");
+ opener.is(e.touches[2].target, s1, "Touch object targeted to light DOM should keep its target as is.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain all the touch objects.");
+ }
+ shadowS1.ontouchstart = function(e) {
+ shadowHandled = true;
+ opener.is(e.targetTouches.length, 3, "Should have all the in targetTouches.");
+ opener.is(e.targetTouches[0].target, shadowS1, "targetTouches should contain two shadow elements.");
+ opener.is(e.targetTouches[1].target, shadowS2, "targetTouches should contain two shadow elements.");
+ opener.is(e.targetTouches[2].target, s1, "targetTouches should contain a slight element.");
+ opener.is(e.touches.length, 3, "touches list should contain all the touch objects.");
+ opener.is(e.changedTouches.length, 3, "changedTouches list should contain all the touch objects.");
+ }
+ var touchArray = createTouchArray([shadowS1, shadowS2, s1]);
+ var touchEvent = new TouchEvent("touchstart",
+ {
+ composed: true,
+ touches: touchArray,
+ targetTouches: touchArray,
+ changedTouches: touchArray
+ });
+ opener.is(touchEvent.targetTouches.length, 3, "Should have 3 entries in targetTouches");
+ shadowS1.dispatchEvent(touchEvent);
+ opener.ok(hostHandled, "Should have called listener on host.");
+ opener.ok(shadowHandled, "Should have called listener on shadow DOM element.");
+ host.ontouchstart = null;
+ shadowS1.ontouchstart = null;
+ next();
+ }
+
+ function start() {
+ winUtils = _getDOMWindowUtils(this);
+ host = document.getElementById("host");
+ shadowRoot = host.attachShadow({ mode: "open" });
+ shadowRoot.innerHTML =
+ "<span id='shadowSpan1'>shadowFoo </span><span id='shadowSpan2'>shadowBar </span><span id='shadowSpan3'>shadowBaz </span><slot></slot>";
+
+ host2 = document.getElementById("host2");
+ shadowRoot2 = host2.attachShadow({ mode: "open" });
+ shadowRoot2.innerHTML =
+ "<span id='shadowSpan1'>shadowFoo </span><span id='shadowSpan2'>shadowBar </span><span id='shadowSpan3'>shadowBaz </span><slot></slot>";
+ next();
+ }
+ </script>
+ <style>
+ </style>
+ </head>
+ <body onload="start();">
+ <div id="nonshadow">
+ <span id="span1">foo </span><span id="span2">bar </span><span id="span3"> baz</span>
+ <input type="date" id="date">
+ </div>
+ <div id="host"><span id="assignedNode"> assigned node </span></div>
+ <div id="host2"><span id="assignedNode2"> assigned node 2 </span></div>
+ </body>
+</html>
diff --git a/dom/events/test/window_bug1447993.html b/dom/events/test/window_bug1447993.html
new file mode 100644
index 0000000000..64bedf658c
--- /dev/null
+++ b/dom/events/test/window_bug1447993.html
@@ -0,0 +1,239 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Test for Bug 1447993</title>
+ <style>
+ #area {
+ background: green;
+ border: 1px solid black;
+ width: 40px;
+ height: 40px;
+ }
+
+ #target {
+ background: blue;
+ border: 1px solid black;
+ width: 20px;
+ height: 20px;
+ margin: 10px;
+ }
+ </style>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script>
+
+ var tests = [
+ topLevelDocumentEventHandling,
+ topLevelDocumentEventHandlingWithTouch,
+ iframeEventHandling,
+ ];
+
+ function next() {
+ if (!tests.length) {
+ opener.done();
+ window.close();
+ } else {
+ var test = tests.shift();
+ requestAnimationFrame(function() { setTimeout(test); });
+ }
+ }
+
+ function start() {
+ next();
+ }
+
+ function topLevelDocumentEventHandling() {
+ var pid;
+ var area = document.getElementById("area");
+ var target = document.getElementById("target");
+ var body = document.body;
+ var html = document.documentElement;
+ var eventLog = [];
+ function captureEvent(e) {
+ eventLog.push([e.type, e.composedPath()]);
+ }
+ var expectedEvents = [
+ ["pointerdown", [ target, area, body, html, document, window ]],
+ ["mousedown", [ target, area, body, html, document, window ]],
+ ["pointerup", [ area, body, html, document, window ]],
+ ["mouseup", [ area, body, html, document, window ]],
+ ["click", [ target, area, body, html, document, window ]],
+ ];
+
+ window.addEventListener("pointerdown",
+ function(e) {
+ captureEvent(e);
+ pid = e.pointerId;
+ area.setPointerCapture(pid);
+ }, { once: true});
+ window.addEventListener("mousedown",
+ function(e) {
+ captureEvent(e);
+ }, { once: true});
+ window.addEventListener("pointerup",
+ function(e) {
+ captureEvent(e);
+ area.releasePointerCapture(pid);
+ }, { once: true});
+ window.addEventListener("mouseup", function(e) {
+ captureEvent(e);
+ }, { once: true});
+ window.addEventListener("click", function(e) {
+ captureEvent(e);
+ }, { once: true});
+
+ synthesizeMouseAtCenter(target, {}, window);
+
+ opener.is(eventLog.length, expectedEvents.length,
+ "[topLevelDocumentEventHandling] Same number events expected.");
+ for (var i = 0; i < eventLog.length; ++i) {
+ opener.is(eventLog[i][0], expectedEvents[i][0],
+ `topLevelDocumentEventHandling ${i}`);
+ for (var j = 0; j < eventLog[i][1].length; ++j) {
+ opener.is(eventLog[i][1][j], expectedEvents[i][1][j],
+ `topLevelDocumentEventHandling ${i} ${j}`);
+ }
+ }
+ next();
+ }
+
+ function topLevelDocumentEventHandlingWithTouch() {
+ var pid;
+ var area = document.getElementById("area");
+ var target = document.getElementById("target");
+ var body = document.body;
+ var html = document.documentElement;
+ var eventLog = [];
+ function captureEvent(e) {
+ eventLog.push([e.type, e.composedPath()]);
+ }
+ var expectedEvents = [
+ ["pointerdown", [ target, area, body, html, document, window ]],
+ ["touchstart", [ target, area, body, html, document, window ]],
+ ["pointerup", [ area, body, html, document, window ]],
+ ["touchend", [ target, area, body, html, document, window ]],
+ /*
+ // Right now touch event initated mousedown/up (and then click) are
+ // dispatched in APZ, and there isn't JS exposed way to test that.
+ ["mousedown", [ target, area, body, html, document, window ]],
+ ["mouseup", [ target, area, body, html, document, window ]],
+ ["click", [ target, area, body, html, document, window ]],*/
+ ];
+
+ window.addEventListener("pointerdown",
+ function(e) {
+ captureEvent(e);
+ pid = e.pointerId;
+ area.setPointerCapture(pid);
+ }, { once: true});
+ window.addEventListener("touchstart", function(e) {
+ captureEvent(e);
+ }, { once: true});
+ window.addEventListener("pointerup",
+ function(e) {
+ captureEvent(e);
+ try {
+ area.releasePointerCapture(pid);
+ } catch(ex) {}
+ }, { once: true});
+ window.addEventListener("touchend", function(e) {
+ captureEvent(e);
+ }, { once: true});
+ /*window.addEventListener("mousedown",
+ function(e) {
+ captureEvent(e);
+ }, { once: true});
+ window.addEventListener("mouseup", function(e) {
+ captureEvent(e);
+ }, { once: true});
+ window.addEventListener("click", function(e) {
+ captureEvent(e);
+ }, { once: true});*/
+
+ synthesizeTouchAtCenter(target, {}, window);
+
+ opener.is(eventLog.length, expectedEvents.length,
+ "[topLevelDocumentEventHandlingWithTouch] Same number events expected.");
+ for (var i = 0; i < eventLog.length; ++i) {
+ opener.is(eventLog[i][0], expectedEvents[i][0],
+ `topLevelDocumentEventHandlingWithTouch ${i}`);
+ for (var j = 0; j < eventLog[i][1].length; ++j) {
+ opener.is(eventLog[i][1][j], expectedEvents[i][1][j],
+ `topLevelDocumentEventHandlingWithTouch ${i} ${j}`);
+ }
+ }
+ next();
+ }
+
+ function iframeEventHandling() {
+ var pid;
+ var iframe = document.getElementById("iframe");
+ var doc = iframe.contentDocument;
+ doc.head.innerHTML = "<style>" + document.getElementsByTagName("style")[0].textContent + "</style>";
+ var area = doc.createElement("div");
+ area.id = "area";
+ var target = doc.createElement("div");
+ target.id = "target";
+ area.appendChild(target);
+ doc.body.appendChild(area);
+ var body = doc.body;
+ var html = doc.documentElement;
+ var win = doc.defaultView;
+ var eventLog = [];
+ function captureEvent(e) {
+ eventLog.push([e.type, e.composedPath()]);
+ }
+ var expectedEvents = [
+ ["pointerdown", [ target, area, body, html, doc, win ]],
+ ["mousedown", [ target, area, body, html, doc, win ]],
+ ["pointerup", [ area, body, html, doc, win ]],
+ ["mouseup", [ area, body, html, doc, win ]],
+ ["click", [ target, area, body, html, doc, win ]],
+ ];
+
+ win.addEventListener("pointerdown",
+ function(e) {
+ captureEvent(e);
+ pid = e.pointerId;
+ area.setPointerCapture(pid);
+ }, { once: true});
+ win.addEventListener("mousedown",
+ function(e) {
+ captureEvent(e);
+ }, { once: true});
+ win.addEventListener("pointerup",
+ function(e) {
+ captureEvent(e);
+ area.releasePointerCapture(pid);
+ }, { once: true});
+ win.addEventListener("mouseup", function(e) {
+ captureEvent(e);
+ }, { once: true});
+ win.addEventListener("click", function(e) {
+ captureEvent(e);
+ }, { once: true});
+
+ synthesizeMouseAtCenter(target, {}, win);
+
+ opener.is(eventLog.length, expectedEvents.length,
+ "[iframeEventHandling] Same number events expected.");
+ for (var i = 0; i < eventLog.length; ++i) {
+ opener.is(eventLog[i][0], expectedEvents[i][0],
+ `iframeEventHandling ${i}`);
+ for (var j = 0; j < eventLog[i][1].length; ++j) {
+ opener.is(eventLog[i][1][j], expectedEvents[i][1][j],
+ `iframeEventHandling ${i} ${j}`);
+ }
+ }
+ next();
+ }
+
+ </script>
+ </head>
+ <body onload="start();">
+ <div id="area">
+ <div id="target"></div>
+ </div>
+ <iframe id="iframe"></iframe>
+ <h5 id="targetOutsideIframe"></h5>
+ </body>
+</html>
diff --git a/dom/events/test/window_bug493251.html b/dom/events/test/window_bug493251.html
new file mode 100644
index 0000000000..d2891a9ef2
--- /dev/null
+++ b/dom/events/test/window_bug493251.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(window.opener.doTest, window);
+ </script>
+</head>
+<body>
+ <input>
+</body>
+</html>
diff --git a/dom/events/test/window_bug617528.xhtml b/dom/events/test/window_bug617528.xhtml
new file mode 100644
index 0000000000..fce6f510b2
--- /dev/null
+++ b/dom/events/test/window_bug617528.xhtml
@@ -0,0 +1,9 @@
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ width="640" height="480">
+
+ <browser id="browser" type="content" primary="true" flex="1" src="about:blank"
+ disablehistory="true"/>
+
+</window>
diff --git a/dom/events/test/window_bug659071.html b/dom/events/test/window_bug659071.html
new file mode 100644
index 0000000000..d2cf1c9ef2
--- /dev/null
+++ b/dom/events/test/window_bug659071.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 659071</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<video id="v" controls></video>
+<script type="application/javascript">
+
+SimpleTest.waitForFocus(startTests, window);
+SimpleTest.requestFlakyTimeout("untriaged");
+
+function is()
+{
+ window.opener.is.apply(window.opener, arguments);
+}
+
+function isnot()
+{
+ window.opener.isnot.apply(window.opener, arguments);
+}
+
+function hitEventLoop(aFunc, aTimes)
+{
+ if (--aTimes) {
+ setTimeout(hitEventLoop, 0, aFunc, aTimes);
+ } else {
+ setTimeout(aFunc, 20);
+ }
+}
+
+function startTests() {
+ SpecialPowers.pushPrefEnv({"set": [["mousewheel.with_control.action", 3]]}, runTests);
+}
+
+function runTests()
+{
+ synthesizeKey("0", { accelKey: true });
+
+ var video = document.getElementById("v");
+ hitEventLoop(function () {
+ is(SpecialPowers.getFullZoom(window), 1.0,
+ "failed to reset zoom");
+ synthesizeWheel(video, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE, ctrlKey: true,
+ deltaX: 0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 });
+ hitEventLoop(function () {
+ isnot(SpecialPowers.getFullZoom(window), 1.0,
+ "failed to zoom by ctrl+wheel");
+
+ synthesizeWheel(video, 10, 10,
+ { deltaMode: WheelEvent.DOM_DELTA_LINE, ctrlKey: true,
+ deltaX: 0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 });
+ hitEventLoop(function () {
+ is(SpecialPowers.getFullZoom(window), 1.0,
+ "failed to reset zoom");
+
+ hitEventLoop(window.opener.finish, 20);
+ }, 20);
+ }, 20);
+ }, 20);
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/events/test/window_wheel_default_action.html b/dom/events/test/window_wheel_default_action.html
new file mode 100644
index 0000000000..d1f3f6962b
--- /dev/null
+++ b/dom/events/test/window_wheel_default_action.html
@@ -0,0 +1,3512 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for default action of WheelEvent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="scrollable" style="overflow: auto; width: 200px; height: 200px;">
+ <div id="clipper" style="margin: 0; padding: 0; overflow: hidden; width: 3000px; height: 3000px;">
+ <div id="scrolled" style="width: 5000px; height: 5000px;">
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+ </div>
+ </div>
+</div>
+<div id="spacerForBody"></div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+// Until the first non-blank paint, the parent will set the opacity of our
+// browser to 0 using the 'blank' attribute.
+// Until the blank attribute is removed, we can't send scroll events.
+SimpleTest.waitForFocus(function() {
+ let chromeScript = SpecialPowers.loadChromeScript(_ => {
+ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ win.requestAnimationFrame(() => {
+ win.gBrowser.selectedBrowser.removeAttribute("blank");
+ win.requestAnimationFrame(() => {
+ sendAsyncMessage("blank-attribute-removed");
+ });
+ });
+ });
+ chromeScript.promiseOneMessage("blank-attribute-removed").then(() => {
+ chromeScript.destroy();
+ runTests();
+ });
+}, window);
+
+SimpleTest.requestLongerTimeout(6);
+SimpleTest.requestFlakyTimeout("untriaged");
+
+var winUtils = SpecialPowers.getDOMWindowUtils(window);
+// grab refresh driver
+winUtils.advanceTimeAndRefresh(100);
+
+var gScrollableElement = document.getElementById("scrollable");
+var gScrolledElement = document.getElementById("scrolled");
+var gSpacerForBodyElement = document.getElementById("spacerForBody");
+
+const kDefaultActionNone = 0;
+const kDefaultActionScroll = 1;
+const kDefaultActionHistory = 2;
+const kDefaultActionZoom = 3;
+const kDefaultActionHorizontalizedScroll = 4;
+
+const kDefaultActionOverrideXNoOverride = -1;
+const kDefaultActionOverrideXNone = kDefaultActionNone;
+const kDefaultActionOverrideXScroll = kDefaultActionScroll;
+const kDefaultActionOverrideXHistory = kDefaultActionHistory;
+const kDefaultActionOverrideXZoom = kDefaultActionZoom;
+
+function is()
+{
+ window.opener.is.apply(window.opener, arguments);
+}
+
+function ok()
+{
+ window.opener.ok.apply(window.opener, arguments);
+}
+
+function sendWheelAndWait(aX, aY, aEvent, aCallback)
+{
+ sendWheelAndPaint(gScrollableElement, aX, aY, aEvent, aCallback);
+}
+
+function hitEventLoop(aFunc, aTimes)
+{
+ winUtils.advanceTimeAndRefresh(100);
+
+ if (--aTimes) {
+ setTimeout(hitEventLoop, 0, aFunc, aTimes);
+ } else {
+ setTimeout(aFunc, 20);
+ }
+}
+
+function onZoomReset(aCallback) {
+ var fullZoom = SpecialPowers.getFullZoom(window);
+ if (fullZoom == 1) {
+ SimpleTest.executeSoon(aCallback);
+ return;
+ }
+ // Zoom causes a resize of the viewport.
+ window.addEventListener("resize", function onResize(event) {
+ is(SpecialPowers.getFullZoom(window), 1, "Zoom should be reset to 1");
+ window.removeEventListener("resize", onResize);
+ SimpleTest.executeSoon(aCallback);
+ });
+}
+
+function setDeltaMultiplierSettings(aSettings, aCallback)
+{
+ SpecialPowers.pushPrefEnv({"set": [
+ ["mousewheel.default.delta_multiplier_x", aSettings.deltaMultiplierX * 100],
+ ["mousewheel.default.delta_multiplier_y", aSettings.deltaMultiplierY * 100],
+ ["mousewheel.default.delta_multiplier_z", aSettings.deltaMultiplierZ * 100],
+ ["mousewheel.with_alt.delta_multiplier_x", aSettings.deltaMultiplierX * 100],
+ ["mousewheel.with_alt.delta_multiplier_y", aSettings.deltaMultiplierY * 100],
+ ["mousewheel.with_alt.delta_multiplier_z", aSettings.deltaMultiplierZ * 100],
+ ["mousewheel.with_control.delta_multiplier_x", aSettings.deltaMultiplierX * 100],
+ ["mousewheel.with_control.delta_multiplier_y", aSettings.deltaMultiplierY * 100],
+ ["mousewheel.with_control.delta_multiplier_z", aSettings.deltaMultiplierZ * 100],
+ ["mousewheel.with_meta.delta_multiplier_x", aSettings.deltaMultiplierX * 100],
+ ["mousewheel.with_meta.delta_multiplier_y", aSettings.deltaMultiplierY * 100],
+ ["mousewheel.with_meta.delta_multiplier_z", aSettings.deltaMultiplierZ * 100],
+ ["mousewheel.with_shift.delta_multiplier_x", aSettings.deltaMultiplierX * 100],
+ ["mousewheel.with_shift.delta_multiplier_y", aSettings.deltaMultiplierY * 100],
+ ["mousewheel.with_shift.delta_multiplier_z", aSettings.deltaMultiplierZ * 100],
+ ["mousewheel.with_win.delta_multiplier_x", aSettings.deltaMultiplierX * 100],
+ ["mousewheel.with_win.delta_multiplier_y", aSettings.deltaMultiplierY * 100],
+ ["mousewheel.with_win.delta_multiplier_z", aSettings.deltaMultiplierZ * 100]
+ ]}, aCallback);
+}
+
+function doTestScroll(aSettings, aCallback)
+{
+ const kNoScroll = 0x00;
+ const kScrollUp = 0x01;
+ const kScrollDown = 0x02;
+ const kScrollLeft = 0x04;
+ const kScrollRight = 0x08;
+
+ const kTests = [
+ { description: "Scroll to bottom by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to bottom by pixel scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to top by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to top by pixel scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to right by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by pixel scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by pixel scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to bottom-right by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollRight },
+ { description: "Scroll to bottom-left by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollLeft },
+ { description: "Scroll to top-left by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollLeft },
+ { description: "Scroll to top-right by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollRight },
+ { description: "Not Scroll by pixel scroll for z",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+
+ { description: "Scroll to bottom by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to bottom by line scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to top by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to top by line scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to right by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by line scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by line scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to bottom-right by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollRight },
+ { description: "Scroll to bottom-left by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollLeft },
+ { description: "Scroll to top-left by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollLeft },
+ { description: "Scroll to top-right by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollRight },
+ { description: "Not Scroll by line scroll for z",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+
+ { description: "Scroll to bottom by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to bottom by page scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to top by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to top by page scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to right by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by page scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by page scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to bottom-right by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollRight },
+ { description: "Scroll to bottom-left by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollLeft },
+ { description: "Scroll to top-left by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollLeft },
+ { description: "Scroll to top-right by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollRight },
+ { description: "Not Scroll by page scroll for z",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+
+ // special cases.
+
+ // momentum scroll should cause scroll even if the action is zoom, but if the default action is none,
+ // shouldn't do it.
+ { description: "Scroll to bottom by momentum pixel scroll when lineOrPageDelta is 0, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to bottom by momentum pixel scroll when lineOrPageDelta is 1, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to top by momentum pixel scroll when lineOrPageDelta is 0, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to top by momentum pixel scroll when lineOrPageDelta is -1, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to right by momentum pixel scroll when lineOrPageDelta is 0, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by momentum pixel scroll when lineOrPageDelta is 1, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by momentum pixel scroll when lineOrPageDelta is 0, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by momentum pixel scroll when lineOrPageDelta is -1, even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to bottom-right by momentum pixel scroll even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollRight },
+ { description: "Scroll to bottom-left by momentum pixel scroll even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollLeft },
+ { description: "Scroll to top-left by momentum pixel scroll even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollLeft },
+ { description: "Scroll to top-right by momentum pixel scroll even if the action is zoom",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollRight },
+ { description: "Not Scroll by momentum pixel scroll for z (action is zoom)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Not Scroll by momentum pixel scroll if default action is none (action is zoom)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: true, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll,
+ prepare (cb) { SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.action", 0]]}, cb); },
+ cleanup (cb) { SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.action", 1]]}, cb); } },
+
+ // momentum scroll should cause scroll even if the action is history, but if the default action is none,
+ // shouldn't do it.
+ { description: "Scroll to bottom by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to bottom by momentum pixel scroll when lineOrPageDelta is 1, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to top by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to top by momentum pixel scroll when lineOrPageDelta is -1, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to right by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by momentum pixel scroll when lineOrPageDelta is 1, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by momentum pixel scroll when lineOrPageDelta is 0, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by momentum pixel scroll when lineOrPageDelta is -1, even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to bottom-right by momentum pixel scroll even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollRight },
+ { description: "Scroll to bottom-left by momentum pixel scroll even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollDown | kScrollLeft },
+ { description: "Scroll to top-left by momentum pixel scroll even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollLeft },
+ { description: "Scroll to top-right by momentum pixel scroll even if the action is history",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kScrollUp | kScrollRight },
+ { description: "Not Scroll by momentum pixel scroll for z (action is history)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Not Scroll by momentum pixel scroll if default action is none (action is history)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: true,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: true, metaKey: false, osKey: false },
+ expected: kNoScroll,
+ prepare (cb) { SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.action", 0]]}, cb); },
+ cleanup (cb) { SpecialPowers.pushPrefEnv({"set": [["mousewheel.default.action", 1]]}, cb); } },
+
+ // Don't scroll along axis whose overflow style is hidden.
+ { description: "Scroll to only bottom by oblique pixel wheel event with overflow-x: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 1, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown,
+ prepare(cb) { gScrollableElement.style.overflowX = "hidden"; cb(); } },
+ { description: "Scroll to only bottom by oblique line wheel event with overflow-x: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 1, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to only bottom by oblique page wheel event with overflow-x: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 1, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to only top by oblique pixel wheel event with overflow-x: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: -16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: -1, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to only top by oblique line wheel event with overflow-x: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: -1, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to only top by oblique page wheel event with overflow-x: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: -1, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp,
+ cleanup (cb) { gScrollableElement.style.overflowX = "auto"; cb(); } },
+ { description: "Scroll to only right by oblique pixel wheel event with overflow-y: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight,
+ prepare(cb) { gScrollableElement.style.overflowY = "hidden"; cb(); } },
+ { description: "Scroll to only right by oblique line wheel event with overflow-y: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to only right by oblique page wheel event with overflow-y: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to only left by oblique pixel wheel event with overflow-y: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: -16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: -1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to only top by oblique line wheel event with overflow-y: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: -1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to only top by oblique page wheel event with overflow-y: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: -1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft,
+ cleanup (cb) { gScrollableElement.style.overflowY = "auto"; cb(); } },
+ { description: "Don't be scrolled by oblique pixel wheel event with overflow: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 1, expectedOverflowDeltaY: 1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll,
+ prepare(cb) { gScrollableElement.style.overflow = "hidden"; cb(); } },
+ { description: "Don't be scrolled by oblique line wheel event with overflow: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 1, expectedOverflowDeltaY: 1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't be scrolled by oblique page wheel event with overflow: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 1, expectedOverflowDeltaY: 1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't be scrolled by oblique pixel wheel event with overflow: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: -16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: -1, expectedOverflowDeltaY: -1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't be scrolled by oblique line wheel event with overflow: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: -1, expectedOverflowDeltaY: -1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't be scrolled by oblique page wheel event with overflow: hidden",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: -1, expectedOverflowDeltaY: -1,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll,
+ cleanup (cb) { gScrollableElement.style.overflow = "auto"; cb(); } },
+
+ // Don't scroll along axis whose overflow style is hidden and overflow delta values should
+ // be zero if there is ancestor scrollable element.
+ { description: "Scroll to only bottom by oblique pixel wheel event with overflow-x: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown,
+ prepare(cb) {
+ gScrollableElement.style.overflowX = "hidden";
+ gScrollableElement.style.position = "fixed";
+ gScrollableElement.style.top = "30px";
+ gScrollableElement.style.left = "30px";
+ // Make body element scrollable.
+ gSpacerForBodyElement.style.width = "5000px";
+ gSpacerForBodyElement.style.height = "5000px";
+ document.documentElement.scrollTop = 500;
+ document.documentElement.scrollLeft = 500;
+ cb();
+ } },
+ { description: "Scroll to only bottom by oblique line wheel event with overflow-x: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to only bottom by oblique page wheel event with overflow-x: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollDown },
+ { description: "Scroll to only top by oblique pixel wheel event with overflow-x: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: -16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to only top by oblique line wheel event with overflow-x: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp },
+ { description: "Scroll to only top by oblique page wheel event with overflow-x: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollUp,
+ cleanup (cb) { gScrollableElement.style.overflowX = "auto"; cb(); } },
+ { description: "Scroll to only right by oblique pixel wheel event with overflow-y: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0, deltaY: 16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight,
+ prepare(cb) { gScrollableElement.style.overflowY = "hidden"; cb(); } },
+ { description: "Scroll to only right by oblique line wheel event with overflow-y: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to only right by oblique page wheel event with overflow-y: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to only left by oblique pixel wheel event with overflow-y: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -16.0, deltaY: -16.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to only top by oblique line wheel event with overflow-y: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to only top by oblique page wheel event with overflow-y: hidden (body is scrollable)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: -1.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft,
+ cleanup (cb) {
+ gScrollableElement.style.overflowY = "auto";
+ gScrollableElement.style.position = "static";
+ gSpacerForBodyElement.style.width = "";
+ gSpacerForBodyElement.style.height = "";
+ cb();
+ } },
+ ];
+
+ var description;
+
+ var currentTestIndex = -1;
+ var isXReverted = (aSettings.deltaMultiplierX < 0);
+ var isYReverted = (aSettings.deltaMultiplierY < 0);
+
+ function doNextTest()
+ {
+ if (++currentTestIndex >= kTests.length) {
+ SimpleTest.executeSoon(aCallback);
+ return;
+ }
+
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+
+ var currentTest = kTests[currentTestIndex];
+ description = "doTestScroll(aSettings=" + aSettings.description + "), " + currentTest.description + ": ";
+ if (currentTest.prepare) {
+ // prepare() can make changes to a page such as
+ // changing the 'overflow' property which requires
+ // a repaint to take effect before sending
+ // scroll-wheel events.
+ currentTest.prepare(doWaitForPaintsAndScroll);
+ } else {
+ doTestCurrentScroll();
+ }
+ }
+
+ function doWaitForPaintsAndScroll() {
+ waitForAllPaintsFlushed(doTestCurrentScroll);
+ }
+
+ function doTestCurrentScroll() {
+ var currentTest = kTests[currentTestIndex];
+ sendWheelAndWait(10, 10, currentTest.event, function () {
+ if (currentTest.expected == kNoScroll) {
+ is(gScrollableElement.scrollTop, 1000, description + "scrolled vertical");
+ is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal");
+ } else {
+ var scrollUp = !isYReverted ? (currentTest.expected & kScrollUp) :
+ (currentTest.expected & kScrollDown);
+ var scrollDown = !isYReverted ? (currentTest.expected & kScrollDown) :
+ (currentTest.expected & kScrollUp);
+ if (scrollUp) {
+ ok(gScrollableElement.scrollTop < 1000, description + "not scrolled up, got " + gScrollableElement.scrollTop);
+ } else if (scrollDown) {
+ ok(gScrollableElement.scrollTop > 1000, description + "not scrolled down, got " + gScrollableElement.scrollTop);
+ } else {
+ is(gScrollableElement.scrollTop, 1000, description + "scrolled vertical");
+ }
+ var scrollLeft = !isXReverted ? (currentTest.expected & kScrollLeft) :
+ (currentTest.expected & kScrollRight);
+ var scrollRight = !isXReverted ? (currentTest.expected & kScrollRight) :
+ (currentTest.expected & kScrollLeft);
+ if (scrollLeft) {
+ ok(gScrollableElement.scrollLeft < 1000, description + "not scrolled to left, got " + gScrollableElement.scrollLeft);
+ } else if (scrollRight) {
+ ok(gScrollableElement.scrollLeft > 1000, description + "not scrolled to right, got " + gScrollableElement.scrollLeft);
+ } else {
+ is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal");
+ }
+ }
+ if (currentTest.cleanup) {
+ currentTest.cleanup(nextStep);
+ } else {
+ nextStep();
+ }
+
+ function nextStep() {
+ winUtils.advanceTimeAndRefresh(100);
+ doNextTest();
+ }
+ });
+ }
+ doNextTest();
+}
+
+function doTestHorizontalizedScroll(aSettings, aCallback)
+{
+ const kNoScroll = 0x00;
+ const kScrollLeft = 0x01;
+ const kScrollRight = 0x02;
+
+ const kTests = [
+ { description: "Scroll to right by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by pixel scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by pixel scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Don't scroll by deltaX (pixel scroll, lineOrPageDelta is 0)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by deltaX (pixel scroll, lineOrPageDelta is 1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by negative deltaX (pixel scroll, lineOrPageDelta is 0)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by negative deltaX (pixel scroll, lineOrPageDelta is -1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Scroll only to right by diagonal pixel scroll (to bottom-right)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll only to right by diagonal pixel scroll (to bottom-left)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll only to left by diagonal pixel scroll (to top-left)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll only to left by pixel scroll (to bottom-right)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Don't scroll by pixel scroll for z-axis",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+
+ { description: "Scroll to right by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by line scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by line scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Don't scroll by deltaX (line scroll, lineOrPageDelta is 0)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by deltaX (line scroll, lineOrPageDelta is 1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by negative deltaX (line scroll, lineOrPageDelta is 0)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by negative deltaY (line scroll, lineOrPageDelta is -1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Scroll only to right by diagonal line scroll (to bottom-right)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll only to right by diagonal line scroll (to bottom-left)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll only to left by diagonal line scroll (to top-left)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll only to left by line scroll (to top-right)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Don't scroll by line scroll for z-axis",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+
+ { description: "Scroll to right by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to right by page scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll to left by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll to left by page scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is 0)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is 1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is 0)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Don't scroll by deltaX (page scroll, lineOrPageDelta is -1)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ { description: "Scroll only to right by diagonal page scroll (to bottom-right)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll only to right by diagonal page scroll (to bottom-left)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollRight },
+ { description: "Scroll only to left by diagonal page scroll (to top-left)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Scroll only to left by diagonal page scroll (to top-right)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kScrollLeft },
+ { description: "Don't scroll by page scroll for z-axis",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: true, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ expected: kNoScroll },
+ ];
+
+ var description;
+
+ var currentTestIndex = -1;
+ // deltaY should cause horizontal scroll and affected by deltaMultiplierY.
+ // So, horizontal scroll amount and direction is affected by deltaMultiplierY.
+ var isXReverted = (aSettings.deltaMultiplierY < 0);
+
+ function doNextTest()
+ {
+ if (++currentTestIndex >= kTests.length) {
+ SimpleTest.executeSoon(aCallback);
+ return;
+ }
+
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+
+ var currentTest = kTests[currentTestIndex];
+ description = "doTestHorizontalizedScroll(aSettings=" + aSettings.description + "), " + currentTest.description + ": ";
+ if (currentTest.prepare) {
+ currentTest.prepare(doTestCurrentScroll);
+ } else {
+ doTestCurrentScroll();
+ }
+ }
+
+ function doTestCurrentScroll() {
+ var currentTest = kTests[currentTestIndex];
+ sendWheelAndWait(10, 10, currentTest.event, function () {
+ is(gScrollableElement.scrollTop, 1000, description + "scrolled vertical");
+ if (currentTest.expected == kNoScroll) {
+ is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal");
+ } else {
+ var scrollLeft = !isXReverted ? (currentTest.expected & kScrollLeft) :
+ (currentTest.expected & kScrollRight);
+ var scrollRight = !isXReverted ? (currentTest.expected & kScrollRight) :
+ (currentTest.expected & kScrollLeft);
+ if (scrollLeft) {
+ ok(gScrollableElement.scrollLeft < 1000, description + "not scrolled to left, got " + gScrollableElement.scrollLeft);
+ } else if (scrollRight) {
+ ok(gScrollableElement.scrollLeft > 1000, description + "not scrolled to right, got " + gScrollableElement.scrollLeft);
+ } else {
+ is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal");
+ }
+ }
+ if (currentTest.cleanup) {
+ currentTest.cleanup(nextStep);
+ } else {
+ nextStep();
+ }
+
+ function nextStep() {
+ winUtils.advanceTimeAndRefresh(100);
+ doNextTest();
+ }
+ });
+ }
+ doNextTest();
+}
+
+// It will take *freaking* long time(maybe *hours*) to test all the writing mode
+// combinations for the scroll target and its root, because there are altogether
+// *one hundred* combinations (10 x 10)!
+//
+// So unless you really don't care a snap on time-consuming testing or a strict
+// criteria is required for testing, it is strongly recommeneded that you
+// comment out at least the writing modes which are marked as "peculiar" before
+// running this test, you are encouraged to also comment out those "uncommon"
+// writing modes in order to further shorten testing time.
+//
+// Note that if you are going to run time-consuming tests without commenting out
+// most of the writing modes, don't forget to increase the value of the
+// parameter in SimpleTest.requestLongerTimeout in this file; otherwise it'll
+// most likely lead you to a timed-out failure.
+//
+// Also note that |isBTT| has nothing to do with the behaviour of auto-dir
+// scrolling, it's just used to set the sign of |kOrigScrollTop|.
+const kWritingModes = [
+ {
+ isRTL: true,
+ isBTT: false,
+ styles: [
+ {
+ writingMode: "horizontal-tb",
+ direction: "rtl",
+ },
+ {
+ writingMode: "vertical-rl",
+ direction: "ltr",
+ },
+ // uncommon
+ //{
+ // writingMode: "sideways-rl",
+ // direction: "ltr",
+ //},
+ ],
+ },
+ {
+ isRTL: false,
+ isBTT: false,
+ styles: [
+ {
+ writingMode: "horizontal-tb",
+ direction: "ltr",
+ },
+ // uncommon
+ //{
+ // writingMode: "vertical-lr",
+ // direction: "ltr",
+ //},
+ // uncommon
+ //{
+ // writingMode: "sideways-lr",
+ // direction: "ltr",
+ //},
+ ],
+ },
+ {
+ isRTL: true,
+ isBTT: true,
+ styles: [
+ // peculiar
+ //{
+ // writingMode: "vertical-rl",
+ // direction: "rtl",
+ //},
+ // peculiar
+ //{
+ // writingMode: "sideways-rl",
+ // direction: "rtl",
+ //},
+ ],
+ },
+ {
+ isRTL: false,
+ isBTT: true,
+ styles: [
+ // peculiar
+ //{
+ // writingMode: "vertical-lr",
+ // direction: "rtl",
+ //},
+ // peculiar
+ //{
+ // writingMode: "sideways-lr",
+ // direction: "rtl",
+ //},
+ ],
+ },
+];
+
+function getFirstWritingModeStyle()
+{
+ if (kWritingModes.length < 1) {
+ return false;
+ }
+ let typeIndex = 0;
+ while (!kWritingModes[typeIndex].styles.length) {
+ typeIndex++;
+ if (typeIndex >= kWritingModes.length) {
+ return false;
+ }
+ }
+ return {typeIndex, styleIndex: 0};
+}
+
+function getNextWritingModeStyle(curStyle)
+{
+ let typeIndex = curStyle.typeIndex;
+ let styleIndex = curStyle.styleIndex + 1;
+ while (typeIndex < kWritingModes.length) {
+ if (styleIndex < kWritingModes[typeIndex].styles.length) {
+ return {typeIndex, styleIndex};
+ }
+ typeIndex++;
+ styleIndex = 0;
+ }
+ return false;
+}
+
+function doTestAutoDirScroll(aSettings, aAutoDirTrait, aCallback)
+{
+ // Go through all the writing-mode combinations for the scroll target and its
+ // root.
+
+ let firstStyle = getFirstWritingModeStyle();
+ if (!firstStyle) {
+ // The whole writing mode list is empty, no need to do any test for auto-dir
+ // scrolling. Go ahead with the subsequent tests.
+ SimpleTest.executeSoon(aCallback);
+ return;
+ }
+
+ // Begin with the first style for both the root and the scroll target.
+ // doTestAutoDirScroll2 will recursively call itself back for every
+ // style combination with getNextWritingModeStyle until all combinations have
+ // been enumerated, and then it will call SimpleTest.executeSoon(aCallback).
+ doTestAutoDirScroll2(aSettings, aAutoDirTrait,
+ firstStyle, firstStyle,
+ aCallback);
+}
+
+function doTestAutoDirScroll2(aSettings, aAutoDirTrait,
+ aStyleForRoot, aStyleForTarget,
+ aCallback)
+{
+ const kStyleTypeForRoot = kWritingModes[aStyleForRoot.typeIndex];
+ const kStyleTypeForTarget = kWritingModes[aStyleForTarget.typeIndex];
+
+ const kStyleForRoot = kStyleTypeForRoot.styles[aStyleForRoot.styleIndex];
+ const kStyleForTarget = kStyleTypeForTarget.styles[aStyleForTarget.styleIndex];
+
+ const kIsRootRTL = kStyleTypeForRoot.isRTL;
+ const kIsTargetRTL = kStyleTypeForTarget.isRTL;
+ // Just used to set the sign of |kOrigScrollTop|, not related to the auto-dir
+ // behaviour.
+ const kIsTargetBTT = kStyleTypeForTarget.isBTT;
+
+ const kOldStyleForRoot = {};
+ const kOldStyleForTarget = {};
+
+ const kHonoursRoot = Boolean(aAutoDirTrait.honoursRoot);
+
+ const kNoScroll = 0x00;
+ const kScrollUp = 0x01;
+ const kScrollDown = 0x02;
+ const kScrollLeft = 0x04;
+ const kScrollRight = 0x08;
+
+ // The four constants indicate the expected result if the scroll direction is
+ // adjusted.
+ const kAdjustedForUp = {};
+ const kAdjustedForDown = {};
+ const kAdjustedForLeft = {};
+ const kAdjustedForRight = {};
+ if (kHonoursRoot ? kIsRootRTL : kIsTargetRTL) {
+ kAdjustedForUp.result = kScrollRight;
+ kAdjustedForUp.desc = "right";
+ kAdjustedForDown.result = kScrollLeft;
+ kAdjustedForDown.desc = "left";
+ kAdjustedForLeft.result = kScrollDown;
+ kAdjustedForLeft.desc = "bottom";
+ kAdjustedForRight.result = kScrollUp;
+ kAdjustedForRight.desc = "top";
+ } else {
+ kAdjustedForUp.result = kScrollLeft;
+ kAdjustedForUp.desc = "left";
+ kAdjustedForDown.result = kScrollRight;
+ kAdjustedForDown.desc = "right";
+ kAdjustedForLeft.result = kScrollUp;
+ kAdjustedForLeft.desc = "top";
+ kAdjustedForRight.result = kScrollDown;
+ kAdjustedForRight.desc = "bottom";
+ }
+
+ const kTests = [
+ // Tests: Test pixel scrolling towards four edges when the target
+ // overflows in both the two directions.
+ // Results: All are unadjusted.
+ // Reason: Auto-dir adjustment never applies to a target which overflows in
+ // both the two directions.
+ { description: "auto-dir scroll to bottom by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown,
+ prepare (cb) {
+ // Static contents will not start from the topleft side in some
+ // writing modes, for ease of coding, we simply absolutely
+ // position the target to the topleft in every case.
+ gScrollableElement.style.position = "absolute";
+ gScrollableElement.style.top = "10px";
+ gScrollableElement.style.left = "10px";
+ SpecialPowers.pushPrefEnv({
+ "set": [["mousewheel.autodir.enabled", true],
+ ["mousewheel.autodir.honourroot", kHonoursRoot]]
+ }, cb);
+ } },
+ { description: "auto-dir scroll to bottom by pixel scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to top by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to top by pixel scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to right by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to right by pixel scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to left by pixel scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+ { description: "auto-dir scroll to left by pixel scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+
+ // Tests: Test diagonal pixel scrolling when the target overflows in both
+ // the two directions.
+ // Results: All are unadjusted.
+ // Reason: Auto-dir adjustment never applies to a target which overflows in
+ // both the two directions, furthermore, it never applies to
+ // diagonal scrolling.
+ { description: "auto-dir scroll to bottom-right by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown | kScrollRight },
+ { description: "auto-dir scroll to bottom-left by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown | kScrollLeft },
+ { description: "auto-dir scroll to top-left by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp | kScrollLeft },
+ { description: "auto-dir scroll to top-right by pixel scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp | kScrollRight },
+
+ // Tests: Test line scrolling towards four edges when the target overflows
+ // in both the two directions.
+ // Results: All are unadjusted.
+ // Reason: Auto-dir adjustment never applies to a target which overflows in
+ // both the two directions.
+ { description: "auto-dir scroll to bottom by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to bottom by line scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to top by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to top by line scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to right by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to right by line scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to left by line scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+ { description: "auto-dir scroll to left by line scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+
+ // Tests: Test diagonal line scrolling when the target overflows in both
+ // the two directions.
+ // Results: All are unadjusted.
+ // Reason: Auto-dir adjustment never applies to a target which overflows in
+ // both the two directions, furthermore, it never applies to
+ // diagonal scrolling.
+ { description: "auto-dir scroll to bottom-right by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown | kScrollRight },
+ { description: "auto-dir scroll to bottom-left by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown | kScrollLeft },
+ { description: "auto-dir scroll to top-left by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp | kScrollLeft },
+ { description: "auto-dir scroll to top-right by line scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp | kScrollRight },
+
+ // Tests: Test page scrolling towards four edges when the target overflows
+ // in both the two directions.
+ // Results: All are unadjusted.
+ // Reason: Auto-dir adjustment never applies to a target which overflows in
+ // both the two directions.
+ { description: "auto-dir scroll to bottom by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to bottom by page scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to top by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to top by page scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to right by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to right by page scroll when lineOrPageDelta is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to left by page scroll even if lineOrPageDelta is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+ { description: "auto-dir scroll to left by page scroll when lineOrPageDelta is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+
+ // Tests: Test diagonal page scrolling when the target overflows in both
+ // the two directions.
+ // Results: All are unadjusted.
+ // Reason: Auto-dir adjustment never applies to a target which overflows in
+ // both the two directions, furthermore, it never applies to
+ // diagonal scrolling.
+ { description: "auto-dir scroll to bottom-right by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown | kScrollRight },
+ { description: "auto-dir scroll to bottom-left by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown | kScrollLeft },
+ { description: "auto-dir scroll to top-left by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp | kScrollLeft },
+ { description: "auto-dir scroll to top-right by page scroll",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp | kScrollRight },
+
+ // The tests above in this function are all for testing a target with two
+ // scrollbars. All of them should not be adjustable.
+ // From here on, the tests below in this function are all for testing a
+ // target with only one scrollbar, either a vertical scrollbar or horizontal
+ // scrollbar. Some of them are adjustable.
+
+ // Tests: Test pixel scrolling towards four edges when the target
+ // overflows only in the horizontal direction.
+ // Results: Vertical wheel scrolls are adjusted to be horizontal whereas the
+ // horizontal wheel scrolls are unadjusted.
+ // Reason: Auto-dir adjustment applies to a target if the target overflows
+ // in only one direction and the direction is orthogonal to the
+ // wheel and deltaZ is zero.
+ { description: "auto-dir scroll to " + kAdjustedForDown.desc +
+ "(originally bottom) by pixel scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForDown.result,
+ prepare (cb) {
+ gScrollableElement.style.overflowX = "auto";
+ gScrollableElement.style.overflowY = "hidden";
+ cb();
+ } },
+ { description: "auto-dir scroll to " + kAdjustedForDown.desc +
+ "(originally bottom) by pixel scroll when lineOrPageDelta is 1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForDown.result },
+ { description: "auto-dir scroll to " + kAdjustedForUp.desc +
+ "(originally top) by pixel scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForUp.result },
+ { description: "auto-dir scroll to " + kAdjustedForUp.desc +
+ "(originally top) by pixel scroll when lineOrPageDelta is -1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForUp.result },
+ { description: "auto-dir scroll to right by pixel scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to right by pixel scroll when lineOrPageDelta is 1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to left by pixel scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+ { description: "auto-dir scroll to left by pixel scroll when lineOrPageDelta is -1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+
+ // Tests: Test pixel scrolling towards four edges when the target
+ // overflows only in the vertical direction.
+ // Results: Horizontal wheel scrolls are adjusted to be vertical whereas the
+ // vertical wheel scrolls are unadjusted.
+ // Reason: Auto-dir adjustment applies to a target if the target overflows
+ // in only one direction and the direction is orthogonal to the
+ // wheel and deltaZ is zero.
+ { description: "auto-dir scroll to bottom by pixel scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown,
+ prepare (cb) {
+ gScrollableElement.style.overflowX = "hidden";
+ gScrollableElement.style.overflowY = "auto";
+ cb();
+ } },
+ { description: "auto-dir scroll to bottom by pixel scroll when lineOrPageDelta is 1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to top by pixel scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to top by pixel scroll when lineOrPageDelta is -1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to " + kAdjustedForRight.desc +
+ "(originally right) by pixel scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForRight.result },
+ { description: "auto-dir scroll to " + kAdjustedForRight.desc +
+ "(originally right) by pixel scroll when lineOrPageDelta is 1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForRight.result },
+ { description: "auto-dir scroll to " + kAdjustedForLeft.desc +
+ "(originally left) by pixel scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForLeft.result },
+ { description: "auto-dir scroll to " + kAdjustedForLeft.desc +
+ "(originally left) by pixel scroll when lineOrPageDelta is -1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForLeft.result },
+
+ // Tests: Test line scrolling towards four edges when the target overflows
+ // only in the horizontal direction.
+ // Results: Vertical wheel scrolls are adjusted to be horizontal whereas the
+ // horizontal wheel scrolls are unadjusted.
+ // Reason: Auto-dir adjustment applies to a target if the target overflows
+ // in only one direction and the direction is orthogonal to the
+ // wheel and deltaZ is zero.
+ { description: "auto-dir scroll to " + kAdjustedForDown.desc +
+ "(originally bottom) by line scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForDown.result,
+ prepare (cb) {
+ gScrollableElement.style.overflowX = "auto";
+ gScrollableElement.style.overflowY = "hidden";
+ cb();
+ } },
+ { description: "auto-dir scroll to " + kAdjustedForDown.desc +
+ "(originally bottom) by line scroll when lineOrPageDelta is 1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForDown.result },
+ { description: "auto-dir scroll to " + kAdjustedForUp.desc +
+ "(originally top) by line scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForUp.result },
+ { description: "auto-dir scroll to " + kAdjustedForUp.desc +
+ "(originally top) by line scroll when lineOrPageDelta is -1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForUp.result },
+ { description: "auto-dir scroll to right by line scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to right by line scroll when lineOrPageDelta is 1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to left by line scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+ { description: "auto-dir scroll to left by line scroll when lineOrPageDelta is -1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+
+ // Tests: Test line scrolling towards four edges when the target overflows
+ // only in the vertical direction.
+ // Results: Horizontal wheel scrolls are adjusted to be vertical whereas the
+ // vertical wheel scrolls are unadjusted.
+ // Reason: Auto-dir adjustment applies to a target if the target overflows
+ // in only one direction and the direction is orthogonal to the
+ // wheel and deltaZ is zero.
+ { description: "auto-dir scroll to bottom by line scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown,
+ prepare (cb) {
+ gScrollableElement.style.overflowX = "hidden";
+ gScrollableElement.style.overflowY = "auto";
+ cb();
+ } },
+ { description: "auto-dir scroll to bottom by line scroll when lineOrPageDelta is 1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to top by line scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to top by line scroll when lineOrPageDelta is -1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to " + kAdjustedForRight.desc +
+ "(originally right) by line scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForRight.result },
+ { description: "auto-dir scroll to " + kAdjustedForRight.desc +
+ "(originally right) by line scroll when lineOrPageDelta is 1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForRight.result },
+ { description: "auto-dir scroll to " + kAdjustedForLeft.desc +
+ "(originally left) by line scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForLeft.result },
+ { description: "auto-dir scroll to " + kAdjustedForLeft.desc +
+ "(originally left) by line scroll when lineOrPageDelta is -1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForLeft.result },
+
+ // Tests: Test page scrolling towards four edges when the target overflows
+ // only in the horizontal direction.
+ // Results: Vertical wheel scrolls are adjusted to be horizontal whereas the
+ // horizontal wheel scrolls are unadjusted.
+ // Reason: Auto-dir adjustment applies to a target if the target overflows
+ // in only one direction and the direction is orthogonal to the
+ // wheel and deltaZ is zero.
+ { description: "auto-dir scroll to " + kAdjustedForDown.desc +
+ "(originally bottom) by page scroll when lineOrPageDelta is 1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForDown.result,
+ prepare (cb) {
+ gScrollableElement.style.overflowX = "auto";
+ gScrollableElement.style.overflowY = "hidden";
+ cb();
+ } },
+ { description: "auto-dir scroll to " + kAdjustedForDown.desc +
+ "(originally bottom) by page scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForDown.result },
+ { description: "auto-dir scroll to " + kAdjustedForUp.desc +
+ "(originally top) by page scroll when lineOrPageDelta is -1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForUp.result },
+ { description: "auto-dir scroll to " + kAdjustedForUp.desc +
+ "(originally top) by page scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForUp.result },
+ { description: "auto-dir scroll to right by page scroll when lineOrPageDelta is 1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to right by page scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollRight },
+ { description: "auto-dir scroll to left by page scroll when lineOrPageDelta is -1, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+ { description: "auto-dir scroll to left by page scroll even if lineOrPageDelta is 0, " +
+ "no vertical scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollLeft },
+
+ // Tests: Test page scrolling towards four edges when the target overflows
+ // only in the vertical direction.
+ // Results: Horizontal wheel scrolls are adjusted to be vertical whereas the
+ // vertical wheel scrolls are unadjusted.
+ // Reason: Auto-dir adjustment applies to a target if the target overflows
+ // in only one direction and the direction is orthogonal to the
+ // wheel and deltaZ is zero.
+ { description: "auto-dir scroll to bottom by page scroll when lineOrPageDelta is 1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown,
+ prepare (cb) {
+ gScrollableElement.style.overflowX = "hidden";
+ gScrollableElement.style.overflowY = "auto";
+ cb();
+ } },
+ { description: "auto-dir scroll to bottom by page scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollDown },
+ { description: "auto-dir scroll to top by page scroll when lineOrPageDelta is -1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to top by page scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: false,
+ expected: kScrollUp },
+ { description: "auto-dir scroll to " + kAdjustedForRight.desc +
+ "(originally right) by page scroll when lineOrPageDelta is 1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForRight.result },
+ { description: "auto-dir scroll to " + kAdjustedForRight.desc +
+ "(originally right) by page scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForRight.result },
+ { description: "auto-dir scroll to " + kAdjustedForLeft.desc +
+ "(originally left) by page scroll when lineOrPageDelta is -1, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForLeft.result },
+ { description: "auto-dir scroll to " + kAdjustedForLeft.desc +
+ "(originally left) by page scroll even if lineOrPageDelta is 0, " +
+ "no horizontal scrollbar",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isMomentum: false,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false, osKey: false },
+ adjusted: true,
+ expected: kAdjustedForLeft.result,
+ cleanup (cb) {
+ gScrollableElement.style.position = "static";
+ gScrollableElement.style.top = "auto";
+ gScrollableElement.style.left = "auto";
+ gScrollableElement.style.overflow = "auto";
+ Object.assign(document.body.style, kOldStyleForRoot);
+ Object.assign(gScrollableElement.style, kOldStyleForTarget);
+ SpecialPowers.pushPrefEnv({"set":
+ [["mousewheel.autodir.enabled",
+ false]]},
+ cb);
+ } },
+ ];
+
+ let styleDescForRoot = "";
+ let styleDescForTarget = "";
+ Object.keys(kStyleForRoot).forEach(function(property)
+ {
+ kOldStyleForRoot[property] = document.body.style[property];
+ document.body.style[property] = kStyleForRoot[property];
+ if ("" !== styleDescForRoot) {
+ styleDescForRoot += " ";
+ }
+ styleDescForRoot += property + ": " + kStyleForRoot[property] + ";";
+ });
+ Object.keys(kStyleForTarget).forEach(function(property)
+ {
+ kOldStyleForTarget[property] = gScrollableElement.style[property];
+ gScrollableElement.style[property] = kStyleForTarget[property];
+ if ("" !== styleDescForTarget) {
+ styleDescForTarget += " ";
+ }
+ styleDescForTarget += property + ": " +
+ kStyleForTarget[property] + ";";
+ });
+
+ let description;
+ let currentTestIndex = -1;
+ let isXReverted = aSettings.deltaMultiplierX < 0;
+ let isYReverted = aSettings.deltaMultiplierY < 0;
+
+ // We are doing a "trick" here:
+ // If the `kHonoursRoot` is true and the scroll target and the root's contents
+ // are both LTR or both RTL, we can safely skip these tests, because the same
+ // behavior is tested when the `kHonoursRoot` is false.
+ if (kHonoursRoot && kIsRootRTL === kIsTargetRTL) {
+ currentTestIndex = kTests.length;
+ }
+
+ const kOrigScrollLeft = kIsTargetRTL ? -1000 : 1000;
+ const kOrigScrollTop = kIsTargetBTT ? -1000 : 1000;
+
+ function doNextTest()
+ {
+ if (++currentTestIndex >= kTests.length) {
+ // The tests for the current writing mode combination have been finished.
+ // Continue the tests for the next writing mode combination, if any.
+ let nextStyleForRoot;
+ let nextStyleForTarget;
+ nextStyleForTarget = getNextWritingModeStyle(aStyleForTarget);
+ if (nextStyleForTarget) {
+ nextStyleForRoot = aStyleForRoot;
+ } else {
+ nextStyleForRoot = getNextWritingModeStyle(aStyleForRoot);
+ if (!nextStyleForRoot) {
+ // All writing mode combinations have been enumerated, so stop
+ // recursively calling doTestAutoDirScroll2, and go ahead with the
+ // subsequent tests.
+ SimpleTest.executeSoon(aCallback);
+ return;
+ }
+ nextStyleForTarget = getFirstWritingModeStyle();
+ }
+ doTestAutoDirScroll2(aSettings, aAutoDirTrait,
+ nextStyleForRoot, nextStyleForTarget,
+ aCallback);
+ return;
+ }
+
+ gScrollableElement.scrollTop = kOrigScrollTop;
+ gScrollableElement.scrollLeft = kOrigScrollLeft;
+
+ var currentTest = kTests[currentTestIndex];
+ description = "doTestAutoDirScroll(aSettings=" + aSettings.description + ", ";
+ if (kHonoursRoot) {
+ description += "{honoursRoot: true}), ";
+ } else {
+ description += "{honoursRoot: false}), ";
+ }
+ description += "root = " + styleDescForRoot + " ";
+ description += "target = " + styleDescForTarget + " ";
+ if (currentTest.adjusted) {
+ description += "adjusted ";
+ } else {
+ description += "unadjusted ";
+ }
+ description += currentTest.description + ": ";
+ if (currentTest.prepare) {
+ currentTest.prepare(doTestCurrentScroll);
+ } else {
+ doTestCurrentScroll();
+ }
+ }
+
+ function doTestCurrentScroll() {
+ var currentTest = kTests[currentTestIndex];
+ sendWheelAndWait(100, 100, currentTest.event, function () {
+ if (currentTest.expected == kNoScroll) {
+ is(gScrollableElement.scrollTop, kOrigScrollTop, description + "scrolled vertical");
+ is(gScrollableElement.scrollLeft, kOrigScrollLeft, description + "scrolled horizontal");
+ } else {
+ // If auto-dir adjustment occurs, temporarily swap |isYReverted| and
+ // |isXReverted|.
+ if (currentTest.adjusted) {
+ [isYReverted, isXReverted] = [isXReverted, isYReverted];
+ }
+ let scrollUp = !isYReverted ? (currentTest.expected & kScrollUp) :
+ (currentTest.expected & kScrollDown);
+ let scrollDown = !isYReverted ? (currentTest.expected & kScrollDown) :
+ (currentTest.expected & kScrollUp);
+ if (scrollUp) {
+ ok(gScrollableElement.scrollTop < kOrigScrollTop,
+ description + "not scrolled up, got " + gScrollableElement.scrollTop);
+ } else if (scrollDown) {
+ ok(gScrollableElement.scrollTop > kOrigScrollTop,
+ description + "not scrolled down, got " + gScrollableElement.scrollTop);
+ } else {
+ is(gScrollableElement.scrollTop, kOrigScrollTop,
+ description + "scrolled vertical");
+ }
+ var scrollLeft = !isXReverted ? (currentTest.expected & kScrollLeft) :
+ (currentTest.expected & kScrollRight);
+ var scrollRight = !isXReverted ? (currentTest.expected & kScrollRight) :
+ (currentTest.expected & kScrollLeft);
+ if (scrollLeft) {
+ ok(gScrollableElement.scrollLeft < kOrigScrollLeft,
+ description + "not scrolled to left, got " + gScrollableElement.scrollLeft);
+ } else if (scrollRight) {
+ ok(gScrollableElement.scrollLeft > kOrigScrollLeft,
+ description + "not scrolled to right, got " + gScrollableElement.scrollLeft);
+ } else {
+ is(gScrollableElement.scrollLeft, kOrigScrollLeft,
+ description + "scrolled horizontal");
+ }
+ // |isYReverted| and |isXReverted| have been temporarily swaped for
+ // auto-dir adjustment, restore them.
+ if (currentTest.adjusted) {
+ [isYReverted, isXReverted] = [isXReverted, isYReverted];
+ }
+ }
+ if (currentTest.cleanup) {
+ currentTest.cleanup(nextStep);
+ } else {
+ nextStep();
+ }
+
+ function nextStep() {
+ winUtils.advanceTimeAndRefresh(100);
+ doNextTest();
+ }
+ });
+ }
+ doNextTest();
+}
+
+function doTestZoom(aSettings, aCallback)
+{
+ if ((aSettings.deltaMultiplierX != 1.0 && aSettings.deltaMultiplierX != -1.0) ||
+ (aSettings.deltaMultiplierY != 1.0 && aSettings.deltaMultiplierY != -1.0)) {
+ todo(false, "doTestZoom doesn't support to test with aSettings=" + aSettings.description);
+ SimpleTest.executeSoon(aCallback);
+ return;
+ }
+
+ const kNone = 0x00;
+ const kPositive = 0x01;
+ const kNegative = 0x02;
+ const kUseX = 0x10;
+ const kUseY = 0x20;
+ const kTests = [
+ { description: "by vertical/positive pixel event when its lineOrPageDeltaY is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by vertical/positive pixel event when its lineOrPageDeltaY is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kPositive | kUseY },
+ { description: "by vertical/negative pixel event when its lineOrPageDeltaY is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by vertical/negative pixel event when its lineOrPageDeltaY is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -8.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNegative | kUseY },
+ { description: "by horizotal/positive pixel event when its lineOrPageDeltaX is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by horizotal/positive pixel event when its lineOrPageDeltaX is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kPositive | kUseX },
+ { description: "by horizotal/negative pixel event when its lineOrPageDeltaX is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by horizotal/negative pixel event when its lineOrPageDeltaX is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -8.0, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNegative | kUseX },
+ { description: "by z pixel event",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 16.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+
+ { description: "by vertical/positive line event when its lineOrPageDeltaY is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by vertical/positive line event when its lineOrPageDeltaY is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kPositive | kUseY },
+ { description: "by vertical/negative line event when its lineOrPageDeltaY is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by vertical/negative line event when its lineOrPageDeltaY is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNegative | kUseY },
+ { description: "by horizotal/positive line event when its lineOrPageDeltaX is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by horizotal/positive line event when its lineOrPageDeltaX is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kPositive | kUseX },
+ { description: "by horizotal/negative line event when its lineOrPageDeltaX is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by horizotal/negative line event when its lineOrPageDeltaX is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNegative | kUseX },
+ { description: "by z line event",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+
+ { description: "by vertical/positive page event when its lineOrPageDeltaY is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by vertical/positive page event when its lineOrPageDeltaY is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kPositive | kUseY },
+ { description: "by vertical/negative page event when its lineOrPageDeltaY is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by vertical/negative page event when its lineOrPageDeltaY is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -0.5, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNegative | kUseY },
+ { description: "by horizotal/positive page event when its lineOrPageDeltaX is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by horizotal/positive page event when its lineOrPageDeltaX is 1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kPositive | kUseX },
+ { description: "by horizotal/negative page event when its lineOrPageDeltaX is 0",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ { description: "by horizotal/negative page event when its lineOrPageDeltaX is -1",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -0.5, deltaY: 0.0, deltaZ: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNegative | kUseX },
+ { description: "by z page event",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 0.0, deltaZ: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0,
+ expectedOverflowDeltaX: 0, expectedOverflowDeltaY: 0 },
+ expected: kNone },
+ ];
+
+ var description, currentTest;
+ var currentTestIndex = -1;
+ var isXReverted = (aSettings.deltaMultiplierX < 0);
+ var isYReverted = (aSettings.deltaMultiplierY < 0);
+
+ function doNextTest() {
+ if (++currentTestIndex >= kTests.length) {
+ SimpleTest.executeSoon(aCallback);
+ return;
+ }
+
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+
+ currentTest = kTests[currentTestIndex];
+ description = "doTestZoom(aSettings=" + aSettings.description + "), ";
+ if (currentTest.expected == kNone) {
+ description += "Shouldn't ";
+ } else {
+ description += "Should ";
+ }
+ description += "zoom " + currentTest.description + ": ";
+
+ var event = currentTest.event;
+ event.ctrlKey = true;
+
+ // NOTE: Zooming might change scrollTop and scrollLeft by rounding fraction.
+ // This test assume that zoom happens synchronously and scrolling
+ // happens asynchronously.
+ var scrollTop = gScrollableElement.scrollTop;
+ var scrollLeft = gScrollableElement.scrollLeft;
+
+ fullZoomChangePromise = new Promise(resolve => {
+ if (currentTest.expected & (kNegative | kPositive)) {
+ // Zoom causes a resize of the viewport.
+ window.addEventListener("resize", function onResize() {
+ if (SpecialPowers.getFullZoom(window) != 1) {
+ window.removeEventListener("resize", onResize);
+ setTimeout(() => resolve(), 0);
+ }
+ });
+ } else {
+ resolve();
+ }
+ });
+
+ sendWheelAndWait(10, 10, event, function () {
+ is(gScrollableElement.scrollTop, scrollTop, description + "scrolled vertical");
+ is(gScrollableElement.scrollLeft, scrollLeft, description + "scrolled horizontal");
+
+ fullZoomChangePromise.then(() => {
+ // When input event prioritization is enabled, the wheel event may be
+ // dispatched to the content process before the message 'FullZoom' to
+ // zoom in/out. Waiting for the event 'FullZoomChange' and then check
+ // the result.
+ if (!(currentTest.expected & (kNegative | kPositive))) {
+ is(SpecialPowers.getFullZoom(window), 1.0, description + "zoomed");
+ } else {
+ var isReverted = (currentTest.expected & kUseX) ? isXReverted :
+ (currentTest.expected & kUseY) ? isYReverted : false;
+ if ((!isReverted && (currentTest.expected & kNegative)) ||
+ (isReverted && (currentTest.expected & kPositive))) {
+ ok(SpecialPowers.getFullZoom(window) > 1.0,
+ description + "not zoomed in, got " + SpecialPowers.getFullZoom(window));
+ } else {
+ ok(SpecialPowers.getFullZoom(window) < 1.0,
+ description + "not zoomed out, got " + SpecialPowers.getFullZoom(window));
+ }
+ }
+ if (SpecialPowers.getFullZoom(window) != 1) {
+ // Only synthesizes key event to reset zoom when necessary to avoid
+ // triggering the next test before the key event is handled. In that
+ // case, the key event may break the next test.
+ synthesizeKey("0", { accelKey: true });
+ }
+ onZoomReset(function () {
+ hitEventLoop(doNextTest, 20);
+ });
+ });
+ });
+ }
+ doNextTest();
+}
+
+function doTestZoomedScroll(aCallback)
+{
+ var zoom = 1.0;
+ function setFullZoom(aWindow, aZoom)
+ {
+ zoom = aZoom;
+ SpecialPowers.setFullZoom(aWindow, aZoom);
+ }
+
+ function prepareTestZoomedPixelScroll()
+ {
+ // Reset zoom and store the scroll amount into the data.
+ synthesizeKey("0", { accelKey: true });
+ zoom = 1.0;
+ onZoomReset(testZoomedPixelScroll);
+ }
+
+ function testZoomedPixelScroll()
+ {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ // Ensure not to be in reflow.
+ hitEventLoop(function () {
+ function mousePixelScrollHandler(aEvent)
+ {
+ if (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS) {
+ is(aEvent.detail, 16,
+ "doTestZoomedScroll: The detail of horizontal MozMousePixelScroll for pixel wheel event is wrong");
+ } else if (aEvent.axis == MouseScrollEvent.VERTICAL_AXIS) {
+ is(aEvent.detail, 16,
+ "doTestZoomedScroll: The detail of vertical MozMousePixelScroll for pixel wheel event is wrong");
+ } else {
+ ok(false, "doTestZoomedScroll: The axis of MozMousePixelScroll for pixel wheel event is invalid, got " + aEvent.axis);
+ }
+ }
+ function wheelHandler(aEvent)
+ {
+ is(aEvent.deltaX, 16.0 / zoom,
+ "doTestZoomedScroll: The deltaX of wheel for pixel is wrong");
+ is(aEvent.deltaY, 16.0 / zoom,
+ "doTestZoomedScroll: The deltaY of wheel for pixel is wrong");
+ }
+ window.addEventListener("MozMousePixelScroll", mousePixelScrollHandler, true);
+ window.addEventListener("wheel", wheelHandler, true);
+ var event = {
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0,
+ deltaY: 16.0,
+ lineOrPageDeltaX: 0,
+ lineOrPageDeltaY: 0
+ };
+ // wait scrolled actually.
+ sendWheelAndWait(10, 10, event, function () {
+ var scrolledX = gScrollableElement.scrollLeft;
+ var scrolledY = gScrollableElement.scrollTop;
+ ok(scrolledX > 1000,
+ "doTestZoomedScroll: scrolledX must be larger than 1000 for pixel wheel event, got " + scrolledX);
+ ok(scrolledY > 1000,
+ "doTestZoomedScroll: scrolledY must be larger than 1000 for pixel wheel event, got " + scrolledY);
+
+ // Zoom
+ setFullZoom(window, 2.0);
+ // Ensure not to be in reflow.
+ hitEventLoop(function () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ var evt = {
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 16.0,
+ deltaY: 16.0,
+ lineOrPageDeltaX: 0,
+ lineOrPageDeltaY: 0
+ };
+ // wait scrolled actually.
+ sendWheelAndWait(10, 10, evt, function () {
+ ok(Math.abs(gScrollableElement.scrollLeft - (1000 + (scrolledX - 1000) / 2)) <= 1,
+ "doTestZoomedScroll: zoomed horizontal scroll amount by pixel wheel event is different from normal, scrollLeft=" +
+ gScrollableElement.scrollLeft + ", scrolledX=" + scrolledX);
+ ok(Math.abs(gScrollableElement.scrollTop - (1000 + (scrolledY - 1000) / 2)) <= 1,
+ "doTestZoomedScroll: zoomed vertical scroll amount by pixel wheel event is different from normal, scrollTop=" +
+ gScrollableElement.scrollTop + ", scrolledY=" + scrolledY);
+ window.removeEventListener("MozMousePixelScroll", mousePixelScrollHandler, true);
+ window.removeEventListener("wheel", wheelHandler, true);
+
+ synthesizeKey("0", { accelKey: true });
+ onZoomReset(prepareTestZoomedLineScroll);
+ });
+ }, 20);
+ });
+ }, 20);
+ }
+
+ function prepareTestZoomedLineScroll()
+ {
+ // Reset zoom and store the scroll amount into the data.
+ synthesizeKey("0", { accelKey: true });
+ zoom = 1.0;
+ onZoomReset(testZoomedLineScroll);
+ }
+ function testZoomedLineScroll()
+ {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ // Ensure not to be in reflow.
+ hitEventLoop(function () {
+ var lineHeightX, lineHeightY;
+ function handler(aEvent)
+ {
+ if (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS) {
+ if (lineHeightX == undefined) {
+ lineHeightX = aEvent.detail;
+ } else {
+ ok(Math.abs(aEvent.detail - lineHeightX) <= 1,
+ "doTestZoomedScroll: The detail of horizontal MozMousePixelScroll for line wheel event is wrong, aEvent.detail=" +
+ aEvent.detail + ", lineHeightX=" + lineHeightX);
+ }
+ } else if (aEvent.axis == MouseScrollEvent.VERTICAL_AXIS) {
+ if (lineHeightY == undefined) {
+ lineHeightY = aEvent.detail;
+ } else {
+ ok(Math.abs(aEvent.detail - lineHeightY) <= 1,
+ "doTestZoomedScroll: The detail of vertical MozMousePixelScroll for line wheel event is wrong, aEvent.detail=" +
+ aEvent.detail + ", lineHeightY=" + lineHeightY);
+ }
+ } else {
+ ok(false, "doTestZoomedScroll: The axis of MozMousePixelScroll for line wheel event is invalid, got " + aEvent.axis);
+ }
+ }
+ window.addEventListener("MozMousePixelScroll", handler, true);
+ var event = {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0,
+ deltaY: 1.0,
+ lineOrPageDeltaX: 1,
+ lineOrPageDeltaY: 1
+ };
+ // wait scrolled actually.
+ sendWheelAndWait(10, 10, event, function () {
+ var scrolledX = gScrollableElement.scrollLeft;
+ var scrolledY = gScrollableElement.scrollTop;
+ ok(scrolledX > 1000,
+ "doTestZoomedScroll: scrolledX must be larger than 1000 for line wheel event, got " + scrolledX);
+ ok(scrolledY > 1000,
+ "doTestZoomedScroll: scrolledY must be larger than 1000 for line wheel event, got " + scrolledY);
+
+ // Zoom
+ setFullZoom(window, 2.0);
+ // Ensure not to be in reflow.
+ hitEventLoop(function () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ var evt = {
+ deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0,
+ deltaY: 1.0,
+ lineOrPageDeltaX: 1,
+ lineOrPageDeltaY: 1
+ };
+ // wait scrolled actually.
+ sendWheelAndWait(10, 10, evt, function () {
+ ok(Math.abs(gScrollableElement.scrollLeft - scrolledX) <= 1,
+ "doTestZoomedScroll: zoomed horizontal scroll amount by line wheel event is different from normal, scrollLeft=" +
+ gScrollableElement.scrollLeft + ", scrolledX=" + scrolledX);
+ ok(Math.abs(gScrollableElement.scrollTop - scrolledY) <= 1,
+ "doTestZoomedScroll: zoomed vertical scroll amount by line wheel event is different from normal, scrollTop=" +
+ gScrollableElement.scrollTop + ", scrolledY=" + scrolledY);
+
+ window.removeEventListener("MozMousePixelScroll", handler, true);
+
+ synthesizeKey("0", { accelKey: true });
+ onZoomReset(aCallback);
+ });
+ }, 20);
+ });
+ }, 20);
+ }
+
+ // XXX It's too difficult to test page scroll because the page scroll amount
+ // is computed by complex logic.
+
+ prepareTestZoomedPixelScroll();
+}
+
+function doTestWholeScroll(aCallback)
+{
+ SpecialPowers.pushPrefEnv({"set": [
+ ["mousewheel.default.delta_multiplier_x", 999999],
+ ["mousewheel.default.delta_multiplier_y", 999999]]},
+ function() { doTestWholeScroll2(aCallback); });
+}
+
+function doTestWholeScroll2(aCallback)
+{
+ const kTests = [
+ { description: "try whole-scroll to top (line)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ expectedScrollTop: 0,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to top when scrollTop is already top-most (line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: -1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ expectedScrollTop: 0,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to bottom (line)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.0, deltaY: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ expectedScrollTop: gScrollableElement.scrollTopMax,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to bottom when scrollTop is already bottom-most (line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0, deltaY: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ expectedScrollTop: gScrollableElement.scrollTopMax,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to left (line)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: 0
+ },
+ { description: "try whole-scroll to left when scrollLeft is already left-most (line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: -1.0, deltaY: 0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: 0
+ },
+ { description: "try whole-scroll to right (line)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: gScrollableElement.scrollLeftMax
+ },
+ { description: "try whole-scroll to right when scrollLeft is already right-most (line)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: gScrollableElement.scrollLeftMax
+ },
+
+
+ { description: "try whole-scroll to top (pixel)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 0,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to top when scrollTop is already top-most (pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: -1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 0,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to bottom (pixel)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0.0, deltaY: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: gScrollableElement.scrollTopMax,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to bottom when scrollTop is already bottom-most (pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 0, deltaY: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: gScrollableElement.scrollTopMax,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to left (pixel)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -1.0, deltaY: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: 0
+ },
+ { description: "try whole-scroll to left when scrollLeft is already left-most (pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: -1.0, deltaY: 0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: 0
+ },
+ { description: "try whole-scroll to right (pixel)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 1.0, deltaY: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: gScrollableElement.scrollLeftMax
+ },
+ { description: "try whole-scroll to right when scrollLeft is already right-most (pixel)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+ deltaX: 1.0, deltaY: 0.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: gScrollableElement.scrollLeftMax
+ },
+
+
+ { description: "try whole-scroll to top (page)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ expectedScrollTop: 0,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to top when scrollTop is already top-most (page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: -1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
+ expectedScrollTop: 0,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to bottom (page)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0.0, deltaY: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ expectedScrollTop: gScrollableElement.scrollTopMax,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to bottom when scrollTop is already bottom-most (page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 0, deltaY: 1.0,
+ lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
+ expectedScrollTop: gScrollableElement.scrollTopMax,
+ expectedScrollLeft: 1000
+ },
+ { description: "try whole-scroll to left (page)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0.0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: 0
+ },
+ { description: "try whole-scroll to left when scrollLeft is already left-most (page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: -1.0, deltaY: 0,
+ lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: 0
+ },
+ { description: "try whole-scroll to right (page)",
+ prepare () {
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ },
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: gScrollableElement.scrollLeftMax
+ },
+ { description: "try whole-scroll to right when scrollLeft is already right-most (page)",
+ event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+ deltaX: 1.0, deltaY: 0.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
+ expectedScrollTop: 1000,
+ expectedScrollLeft: gScrollableElement.scrollLeftMax
+ },
+ ];
+
+ var index = 0;
+
+ function doIt()
+ {
+ const kTest = kTests[index];
+ if (kTest.prepare) {
+ kTest.prepare();
+ }
+ sendWheelAndWait(10, 10, kTest.event, function () {
+ is(gScrollableElement.scrollTop, kTest.expectedScrollTop,
+ "doTestWholeScroll, " + kTest.description + ": unexpected scrollTop");
+ is(gScrollableElement.scrollLeft, kTest.expectedScrollLeft,
+ "doTestWholeScroll, " + kTest.description + ": unexpected scrollLeft");
+ if (++index == kTests.length) {
+ SimpleTest.executeSoon(aCallback);
+ } else {
+ doIt();
+ }
+ });
+ }
+ doIt();
+}
+
+function doTestActionOverride(aCallback)
+{
+ const kNoScroll = 0x00;
+ const kScrollUp = 0x01;
+ const kScrollDown = 0x02;
+ const kScrollLeft = 0x04;
+ const kScrollRight = 0x08;
+
+ const kTests = [
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNoOverride,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNone,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXScroll,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNoOverride,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNone,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXScroll,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNoOverride,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.5,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNone,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.5,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXScroll,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.5,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNoOverride,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.5,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNone,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.5,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXScroll,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 1.0, deltaY: 0.5,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNoOverride,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXNone,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionScroll, override_x: kDefaultActionOverrideXScroll,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kScrollDown | kScrollRight
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNoOverride,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXNone,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ { action: kDefaultActionNone, override_x: kDefaultActionOverrideXScroll,
+ event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+ deltaX: 0.5, deltaY: 1.0,
+ lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 },
+ expected: kNoScroll
+ },
+ ];
+
+ var index = 0;
+
+ function doIt()
+ {
+ const kTest = kTests[index];
+ SpecialPowers.pushPrefEnv({"set": [
+ ["mousewheel.default.action", kTest.action],
+ ["mousewheel.default.action.override_x", kTest.override_x]]},
+ doIt2
+ );
+ }
+
+ function doIt2()
+ {
+ const kTest = kTests[index];
+ description = "doTestActionOverride(action=" + kTest.action + ", " +
+ "override_x=" + kTest.override_x + ", " +
+ "deltaX=" + kTest.event.deltaX + ", " +
+ "deltaY=" + kTest.event.deltaY + "): ";
+ gScrollableElement.scrollTop = 1000;
+ gScrollableElement.scrollLeft = 1000;
+ sendWheelAndWait(10, 10, kTest.event, function () {
+ if (kTest.expected & kScrollUp) {
+ ok(gScrollableElement.scrollTop < 1000, description + "not scrolled up, got " + gScrollableElement.scrollTop);
+ } else if (kTest.expected & kScrollDown) {
+ ok(gScrollableElement.scrollTop > 1000, description + "not scrolled down, got " + gScrollableElement.scrollTop);
+ } else {
+ is(gScrollableElement.scrollTop, 1000, description + "scrolled vertical");
+ }
+ if (kTest.expected & kScrollLeft) {
+ ok(gScrollableElement.scrollLeft < 1000, description + "not scrolled to left, got " + gScrollableElement.scrollLeft);
+ } else if (kTest.expected & kScrollRight) {
+ ok(gScrollableElement.scrollLeft > 1000, description + "not scrolled to right, got " + gScrollableElement.scrollLeft);
+ } else {
+ is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal");
+ }
+ if (++index == kTests.length) {
+ SimpleTest.executeSoon(aCallback);
+ } else {
+ doIt();
+ }
+ });
+ }
+ doIt();
+}
+
+function runTests()
+{
+ SpecialPowers.pushPrefEnv({"set": [
+ ["test.events.async.enabled", true],
+ ["general.smoothScroll", false],
+ ["mousewheel.default.action", kDefaultActionScroll],
+ ["mousewheel.default.action.override_x", kDefaultActionOverrideXNoOverride],
+ ["mousewheel.with_shift.action", kDefaultActionHorizontalizedScroll],
+ ["mousewheel.with_shift.action.override_x", kDefaultActionOverrideXNoOverride],
+ ["mousewheel.with_control.action", kDefaultActionZoom],
+ ["mousewheel.with_control.action.override_x", kDefaultActionOverrideXNoOverride],
+ ["mousewheel.with_alt.action", kDefaultActionHistory],
+ ["mousewheel.with_alt.action.override_x", kDefaultActionOverrideXNoOverride]]},
+ runTests2);
+}
+
+function runTests2()
+{
+ const kSettings = [
+ { description: "all delta values are not customized",
+ deltaMultiplierX: 1.0, deltaMultiplierY: 1.0, deltaMultiplierZ: 1.0 },
+ { description: "deltaX is reverted",
+ deltaMultiplierX: -1.0, deltaMultiplierY: 1.0, deltaMultiplierZ: 1.0 },
+ { description: "deltaY is reverted",
+ deltaMultiplierX: 1.0, deltaMultiplierY: -1.0, deltaMultiplierZ: 1.0 },
+ // Unless you really don't care a snap on time-consuming testing or a strict
+ // criteria is required for testing, it is strongly recommeneded that you
+ // comment the unrealistic case out.
+ //{ description: "deltaZ is reverted",
+ // deltaMultiplierX: 1.0, deltaMultiplierY: 1.0, deltaMultiplierZ: -1.0 },*/
+ { description: "deltaX is 2.0",
+ deltaMultiplierX: 2.0, deltaMultiplierY: 1.0, deltaMultiplierZ: 1.0 },
+ { description: "deltaY is 2.0",
+ deltaMultiplierX: 1.0, deltaMultiplierY: 2.0, deltaMultiplierZ: 1.0 },
+ // Unless you really don't care a snap on time-consuming testing or a strict
+ // criteria is required for testing, it is strongly recommeneded that you
+ // comment the unrealistic case out.
+ //{ description: "deltaZ is 2.0",
+ // deltaMultiplierX: 1.0, deltaMultiplierY: 1.0, deltaMultiplierZ: 2.0 },
+ //{ description: "deltaX is -2.0",
+ // deltaMultiplierX: -2.0, deltaMultiplierY: 1.0, deltaMultiplierZ: 1.0 },
+ //{ description: "deltaY is -2.0",
+ // deltaMultiplierX: 1.0, deltaMultiplierY: -2.0, deltaMultiplierZ: 1.0 },
+ //{ description: "deltaZ is -2.0",
+ // deltaMultiplierX: 1.0, deltaMultiplierY: 1.0, deltaMultiplierZ: -2.0 },
+ ];
+
+ var index = 0;
+
+ function doTest() {
+ setDeltaMultiplierSettings(kSettings[index], function () {
+ doTestScroll(kSettings[index], function () {
+ doTestAutoDirScroll(kSettings[index], {honoursRoot: false}, function () {
+ doTestAutoDirScroll(kSettings[index], {honoursRoot: true}, function () {
+ doTestHorizontalizedScroll(kSettings[index], function() {
+ doTestZoom(kSettings[index], function() {
+ if (++index == kSettings.length) {
+ setDeltaMultiplierSettings(kSettings[0], function() {
+ doTestZoomedScroll(function() {
+ doTestWholeScroll(function() {
+ doTestActionOverride(function() {
+ finishTests();
+ });
+ });
+ });
+ });
+ } else {
+ doTest();
+ }
+ });
+ });
+ });
+ });
+ });
+ });
+ }
+ doTest();
+}
+
+function finishTests()
+{
+ winUtils.restoreNormalRefresh();
+
+ window.opener.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>