summaryrefslogtreecommitdiffstats
path: root/dom/base/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/base/test
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/base/test')
-rw-r--r--dom/base/test/.eslintrc.js12
-rw-r--r--dom/base/test/345339_iframe.html29
-rw-r--r--dom/base/test/Ahem.ttfbin0 -> 12480 bytes
-rw-r--r--dom/base/test/FAIL.html1
-rw-r--r--dom/base/test/PASS.html1
-rw-r--r--dom/base/test/accesscontrol.resource7
-rw-r--r--dom/base/test/accesscontrol.resource^headers^5
-rw-r--r--dom/base/test/audio.oggbin0 -> 14293 bytes
-rw-r--r--dom/base/test/badContentType.eventsource5
-rw-r--r--dom/base/test/badContentType.eventsource^headers^1
-rw-r--r--dom/base/test/badHTTPResponseCode.eventsource5
-rw-r--r--dom/base/test/badHTTPResponseCode.eventsource^headers^2
-rw-r--r--dom/base/test/badMessageEvent.eventsource4
-rw-r--r--dom/base/test/badMessageEvent.eventsource^headers^1
-rw-r--r--dom/base/test/badMessageEvent2.eventsource5
-rw-r--r--dom/base/test/badMessageEvent2.eventsource^headers^1
-rw-r--r--dom/base/test/browser.ini112
-rw-r--r--dom/base/test/browser_aboutnewtab_process_selection.js137
-rw-r--r--dom/base/test/browser_blocking_image.js183
-rw-r--r--dom/base/test/browser_bug1011748.js31
-rw-r--r--dom/base/test/browser_bug1058164.js238
-rw-r--r--dom/base/test/browser_bug1303838.js368
-rw-r--r--dom/base/test/browser_bug1554070.js49
-rw-r--r--dom/base/test/browser_bug1691214.js122
-rw-r--r--dom/base/test/browser_bug1703472.js68
-rw-r--r--dom/base/test/browser_bug902350.js56
-rw-r--r--dom/base/test/browser_chromeutils_getalldomprocesses.js62
-rw-r--r--dom/base/test/browser_chromeutils_isdomobject.js115
-rw-r--r--dom/base/test/browser_data_documents_aboutmemory.js20
-rw-r--r--dom/base/test/browser_force_process_selector.js38
-rw-r--r--dom/base/test/browser_form_validity_popup_submit.js55
-rw-r--r--dom/base/test/browser_inputStream_structuredClone.js72
-rw-r--r--dom/base/test/browser_messagemanager_loadprocessscript.js193
-rw-r--r--dom/base/test/browser_messagemanager_targetframeloader.js36
-rw-r--r--dom/base/test/browser_messagemanager_unload.js131
-rw-r--r--dom/base/test/browser_multiple_popups.html63
-rw-r--r--dom/base/test/browser_multiple_popups.js296
-rw-r--r--dom/base/test/browser_outline_refocus.js65
-rw-r--r--dom/base/test/browser_page_load_event_telemetry.js46
-rw-r--r--dom/base/test/browser_pagehide_on_tab_close.js21
-rw-r--r--dom/base/test/browser_promiseDocumentFlushed.js292
-rw-r--r--dom/base/test/browser_refresh_content.js127
-rw-r--r--dom/base/test/browser_state_notifications.js193
-rw-r--r--dom/base/test/browser_timeout_throttling_with_audio_playback.js73
-rw-r--r--dom/base/test/browser_use_counters.js348
-rw-r--r--dom/base/test/browser_user_input_handling_delay.js82
-rw-r--r--dom/base/test/browser_user_input_handling_delay_aboutblank.js58
-rw-r--r--dom/base/test/browser_user_input_handling_delay_bfcache.js107
-rw-r--r--dom/base/test/browser_user_input_handling_delay_invisible_iframe.js78
-rw-r--r--dom/base/test/browser_user_input_handling_delay_reload_ticks.js54
-rw-r--r--dom/base/test/browser_xml_toggle.js24
-rw-r--r--dom/base/test/bug1576154.sjs8
-rw-r--r--dom/base/test/bug1739957.sjs10
-rw-r--r--dom/base/test/bug282547.sjs8
-rw-r--r--dom/base/test/bug298064-subframe.html24
-rw-r--r--dom/base/test/bug313646.txt1
-rw-r--r--dom/base/test/bug382113_object.html6
-rw-r--r--dom/base/test/bug403852_fileOpener.js24
-rw-r--r--dom/base/test/bug419132.html22
-rw-r--r--dom/base/test/bug426308-redirect.sjs4
-rw-r--r--dom/base/test/bug435425.sjs25
-rw-r--r--dom/base/test/bug435425_redirect.sjs4
-rw-r--r--dom/base/test/bug444322.js0
-rw-r--r--dom/base/test/bug444322.txt0
-rw-r--r--dom/base/test/bug444546.sjs21
-rw-r--r--dom/base/test/bug455629-helper.svg6
-rw-r--r--dom/base/test/bug457746.sjs10
-rw-r--r--dom/base/test/bug461735-post-redirect.js3
-rw-r--r--dom/base/test/bug461735-redirect1.sjs8
-rw-r--r--dom/base/test/bug461735-redirect2.sjs8
-rw-r--r--dom/base/test/bug466080.sjs14
-rw-r--r--dom/base/test/bug466409-empty.css0
-rw-r--r--dom/base/test/bug466409-page.html12
-rw-r--r--dom/base/test/bug475156.sjs23
-rw-r--r--dom/base/test/bug482935.sjs12
-rw-r--r--dom/base/test/bug540854.sjs21
-rw-r--r--dom/base/test/bug578096LoadChromeScript.js20
-rw-r--r--dom/base/test/bug638112-response.txtbin0 -> 247 bytes
-rw-r--r--dom/base/test/bug638112.sjs24
-rw-r--r--dom/base/test/bug696301-script-1.js3
-rw-r--r--dom/base/test/bug696301-script-1.js^headers^1
-rw-r--r--dom/base/test/bug696301-script-2.js3
-rw-r--r--dom/base/test/bug704320.sjs396
-rw-r--r--dom/base/test/bug704320_counter.sjs96
-rw-r--r--dom/base/test/bug819051.sjs9
-rw-r--r--dom/base/test/chrome.ini42
-rw-r--r--dom/base/test/chrome/bug418986-1.js88
-rw-r--r--dom/base/test/chrome/bug421622-referer.sjs9
-rw-r--r--dom/base/test/chrome/bug884693.sjs8
-rw-r--r--dom/base/test/chrome/chrome.ini84
-rw-r--r--dom/base/test/chrome/clonedoc/chrome.manifest1
-rw-r--r--dom/base/test/chrome/clonedoc/content/doc.xml4
-rw-r--r--dom/base/test/chrome/custom_element_ep.js14
-rw-r--r--dom/base/test/chrome/file_bug1139964.xhtml60
-rw-r--r--dom/base/test/chrome/file_bug1209621.xhtml85
-rw-r--r--dom/base/test/chrome/file_bug549682.xhtml214
-rw-r--r--dom/base/test/chrome/file_bug616841.xhtml63
-rw-r--r--dom/base/test/chrome/file_bug816340.xhtml70
-rw-r--r--dom/base/test/chrome/file_bug990812-1.xhtml61
-rw-r--r--dom/base/test/chrome/file_bug990812-2.xhtml56
-rw-r--r--dom/base/test/chrome/file_bug990812-3.xhtml68
-rw-r--r--dom/base/test/chrome/file_bug990812-4.xhtml63
-rw-r--r--dom/base/test/chrome/file_bug990812-5.xhtml74
-rw-r--r--dom/base/test/chrome/file_bug990812.xhtml55
-rw-r--r--dom/base/test/chrome/file_document-element-inserted-inner.xhtml1
-rw-r--r--dom/base/test/chrome/file_document-element-inserted.xhtml3
-rw-r--r--dom/base/test/chrome/file_title.xhtml1
-rw-r--r--dom/base/test/chrome/fileconstructor_file.pngbin0 -> 95 bytes
-rw-r--r--dom/base/test/chrome/frame_custom_element_content.html5
-rw-r--r--dom/base/test/chrome/nochrome_bug1346936.html3
-rw-r--r--dom/base/test/chrome/nochrome_bug1346936.js4
-rw-r--r--dom/base/test/chrome/nochrome_bug1346936.js^headers^1
-rw-r--r--dom/base/test/chrome/nochrome_bug765993.html3
-rw-r--r--dom/base/test/chrome/nochrome_bug765993.js4
-rw-r--r--dom/base/test/chrome/nochrome_bug765993.js^headers^1
-rw-r--r--dom/base/test/chrome/test_bug1063837.xhtml36
-rw-r--r--dom/base/test/chrome/test_bug1098074_throw_from_ReceiveMessage.xhtml46
-rw-r--r--dom/base/test/chrome/test_bug1139964.xhtml32
-rw-r--r--dom/base/test/chrome/test_bug120684.xhtml80
-rw-r--r--dom/base/test/chrome/test_bug1209621.xhtml34
-rw-r--r--dom/base/test/chrome/test_bug1339722.html86
-rw-r--r--dom/base/test/chrome/test_bug1346936.html61
-rw-r--r--dom/base/test/chrome/test_bug206691.xhtml32
-rw-r--r--dom/base/test/chrome/test_bug289714.xhtml33
-rw-r--r--dom/base/test/chrome/test_bug339494.xhtml62
-rw-r--r--dom/base/test/chrome/test_bug357450.xhtml56
-rw-r--r--dom/base/test/chrome/test_bug380418.html37
-rw-r--r--dom/base/test/chrome/test_bug380418.html^headers^4
-rw-r--r--dom/base/test/chrome/test_bug383430.html38
-rw-r--r--dom/base/test/chrome/test_bug418986-1.xhtml25
-rw-r--r--dom/base/test/chrome/test_bug421622.xhtml34
-rw-r--r--dom/base/test/chrome/test_bug429785.xhtml55
-rw-r--r--dom/base/test/chrome/test_bug430050.xhtml50
-rw-r--r--dom/base/test/chrome/test_bug467123.xhtml44
-rw-r--r--dom/base/test/chrome/test_bug473284.xhtml83
-rw-r--r--dom/base/test/chrome/test_bug549682.xhtml32
-rw-r--r--dom/base/test/chrome/test_bug571390.xhtml42
-rw-r--r--dom/base/test/chrome/test_bug616841.xhtml30
-rw-r--r--dom/base/test/chrome/test_bug635835.xhtml36
-rw-r--r--dom/base/test/chrome/test_bug682305.html150
-rw-r--r--dom/base/test/chrome/test_bug683852.xhtml87
-rw-r--r--dom/base/test/chrome/test_bug752226-3.xhtml28
-rw-r--r--dom/base/test/chrome/test_bug752226-4.xhtml28
-rw-r--r--dom/base/test/chrome/test_bug765993.html61
-rw-r--r--dom/base/test/chrome/test_bug780199.xhtml51
-rw-r--r--dom/base/test/chrome/test_bug780529.xhtml36
-rw-r--r--dom/base/test/chrome/test_bug800386.xhtml65
-rw-r--r--dom/base/test/chrome/test_bug816340.xhtml30
-rw-r--r--dom/base/test/chrome/test_bug884693.xhtml82
-rw-r--r--dom/base/test/chrome/test_bug914381.html58
-rw-r--r--dom/base/test/chrome/test_bug990812.xhtml42
-rw-r--r--dom/base/test/chrome/test_chromeOuterWindowID.xhtml137
-rw-r--r--dom/base/test/chrome/test_custom_element_content.xhtml55
-rw-r--r--dom/base/test/chrome/test_custom_element_ep.xhtml41
-rw-r--r--dom/base/test/chrome/test_document-element-inserted.xhtml54
-rw-r--r--dom/base/test/chrome/test_domparsing.xhtml145
-rw-r--r--dom/base/test/chrome/test_fileconstructor.xhtml86
-rw-r--r--dom/base/test/chrome/test_getElementsWithGrid.html121
-rw-r--r--dom/base/test/chrome/test_input_value_set_preserve_undo.xhtml37
-rw-r--r--dom/base/test/chrome/test_nsITextInputProcessor.xhtml29
-rw-r--r--dom/base/test/chrome/test_permission_hasValidTransientUserActivation.xhtml91
-rw-r--r--dom/base/test/chrome/test_range_getClientRectsAndTexts.html74
-rw-r--r--dom/base/test/chrome/test_swapFrameLoaders.xhtml25
-rw-r--r--dom/base/test/chrome/test_title.xhtml29
-rw-r--r--dom/base/test/chrome/test_windowroot.xhtml18
-rw-r--r--dom/base/test/chrome/title_window.xhtml197
-rw-r--r--dom/base/test/chrome/window_chromeOuterWindowID.xhtml14
-rw-r--r--dom/base/test/chrome/window_nsITextInputProcessor.xhtml4750
-rw-r--r--dom/base/test/chrome/window_swapFrameLoaders.xhtml225
-rw-r--r--dom/base/test/common_postMessages.js393
-rw-r--r--dom/base/test/copypaste.js553
-rw-r--r--dom/base/test/delayedServerEvents.sjs56
-rw-r--r--dom/base/test/dummy.html9
-rw-r--r--dom/base/test/embed_bug455472.html1
-rw-r--r--dom/base/test/empty.html0
-rw-r--r--dom/base/test/eventsource.resource22
-rw-r--r--dom/base/test/eventsource.resource^headers^3
-rw-r--r--dom/base/test/eventsource_message.sjs12
-rw-r--r--dom/base/test/eventsource_reconnect.sjs18
-rw-r--r--dom/base/test/eventsource_redirect.resource2
-rw-r--r--dom/base/test/eventsource_redirect.resource^headers^3
-rw-r--r--dom/base/test/eventsource_redirect_to.resource4
-rw-r--r--dom/base/test/eventsource_redirect_to.resource^headers^3
-rw-r--r--dom/base/test/eventsource_worker.js6
-rw-r--r--dom/base/test/fake_plugin.tst1
-rw-r--r--dom/base/test/file1_setting_opener.html1
-rw-r--r--dom/base/test/file2_setting_opener.html1
-rw-r--r--dom/base/test/file3_setting_opener.html1
-rw-r--r--dom/base/test/file4_setting_opener.html1
-rw-r--r--dom/base/test/file_audioLoop.html2
-rw-r--r--dom/base/test/file_audioLoopInIframe.html2
-rw-r--r--dom/base/test/file_blocking_image.html10
-rw-r--r--dom/base/test/file_browser_refresh_content.html41
-rw-r--r--dom/base/test/file_browser_refresh_expired_resource.sjs13
-rw-r--r--dom/base/test/file_browser_refresh_iframe.sjs13
-rw-r--r--dom/base/test/file_browser_refresh_image.sjs38
-rw-r--r--dom/base/test/file_browser_refresh_non_cacheable.sjs6
-rw-r--r--dom/base/test/file_bug1008126_worker.js151
-rw-r--r--dom/base/test/file_bug1011748_OK.sjs4
-rw-r--r--dom/base/test/file_bug1011748_redirect.sjs5
-rw-r--r--dom/base/test/file_bug1091883_frame.html13
-rw-r--r--dom/base/test/file_bug1091883_subframe.html6
-rw-r--r--dom/base/test/file_bug1091883_target.html13
-rw-r--r--dom/base/test/file_bug1100912.html150
-rw-r--r--dom/base/test/file_bug1198095.js38
-rw-r--r--dom/base/test/file_bug1250148.sjs73
-rw-r--r--dom/base/test/file_bug1268962.sjs92
-rw-r--r--dom/base/test/file_bug1274806.html33
-rw-r--r--dom/base/test/file_bug1303838.html34
-rw-r--r--dom/base/test/file_bug1303838_target.html21
-rw-r--r--dom/base/test/file_bug1303838_target_bar.html1
-rw-r--r--dom/base/test/file_bug1303838_target_baz.html1
-rw-r--r--dom/base/test/file_bug1303838_target_foo.html1
-rw-r--r--dom/base/test/file_bug1303838_target_ibar.html1
-rw-r--r--dom/base/test/file_bug1303838_target_ibaz.html1
-rw-r--r--dom/base/test/file_bug1303838_target_ifoo.html1
-rw-r--r--dom/base/test/file_bug1303838_with_iframe.html13
-rw-r--r--dom/base/test/file_bug1554070_1.html14
-rw-r--r--dom/base/test/file_bug1554070_2.html13
-rw-r--r--dom/base/test/file_bug1639328.html8
-rw-r--r--dom/base/test/file_bug1691214.html4
-rw-r--r--dom/base/test/file_bug1700871.html18
-rw-r--r--dom/base/test/file_bug1703472.html6
-rw-r--r--dom/base/test/file_bug28293.sjs4
-rw-r--r--dom/base/test/file_bug326337.xml1
-rw-r--r--dom/base/test/file_bug326337_inner.html44
-rw-r--r--dom/base/test/file_bug326337_outer.html15
-rw-r--r--dom/base/test/file_bug357450.js74
-rw-r--r--dom/base/test/file_bug416317.xhtml1468
-rw-r--r--dom/base/test/file_bug426646-1.html37
-rw-r--r--dom/base/test/file_bug426646-2.html65
-rw-r--r--dom/base/test/file_bug428847-1.xhtml4
-rw-r--r--dom/base/test/file_bug428847-2.xhtml4
-rw-r--r--dom/base/test/file_bug498897.css1
-rw-r--r--dom/base/test/file_bug498897.html23
-rw-r--r--dom/base/test/file_bug498897.html^headers^1
-rw-r--r--dom/base/test/file_bug503473-frame.sjs22
-rw-r--r--dom/base/test/file_bug503481.sjs54
-rw-r--r--dom/base/test/file_bug503481b_inner.html62
-rw-r--r--dom/base/test/file_bug518104.js3
-rw-r--r--dom/base/test/file_bug541937.html7
-rw-r--r--dom/base/test/file_bug541937.xhtml12
-rw-r--r--dom/base/test/file_bug557892.html25
-rw-r--r--dom/base/test/file_bug562137.txt1
-rw-r--r--dom/base/test/file_bug590812-ref.xhtml3
-rw-r--r--dom/base/test/file_bug590812.xml1
-rw-r--r--dom/base/test/file_bug590870.html16
-rw-r--r--dom/base/test/file_bug601803a.html22
-rw-r--r--dom/base/test/file_bug601803b.html11
-rw-r--r--dom/base/test/file_bug604660-1.xml3
-rw-r--r--dom/base/test/file_bug604660-2.xsl19
-rw-r--r--dom/base/test/file_bug604660-3.js1
-rw-r--r--dom/base/test/file_bug604660-4.js1
-rw-r--r--dom/base/test/file_bug604660-5.xml2
-rw-r--r--dom/base/test/file_bug604660-6.xsl9
-rw-r--r--dom/base/test/file_bug622088.sjs5
-rw-r--r--dom/base/test/file_bug622088_inner.html38
-rw-r--r--dom/base/test/file_bug675121.sjs19
-rw-r--r--dom/base/test/file_bug687859-16.jsbin0 -> 64 bytes
-rw-r--r--dom/base/test/file_bug687859-16.js^headers^1
-rw-r--r--dom/base/test/file_bug687859-bom.js1
-rw-r--r--dom/base/test/file_bug687859-bom.js^headers^1
-rw-r--r--dom/base/test/file_bug687859-charset.js1
-rw-r--r--dom/base/test/file_bug687859-http.js1
-rw-r--r--dom/base/test/file_bug687859-http.js^headers^1
-rw-r--r--dom/base/test/file_bug687859-inherit.js1
-rw-r--r--dom/base/test/file_bug692434.xml1
-rw-r--r--dom/base/test/file_bug704320_preload_attr.html32
-rw-r--r--dom/base/test/file_bug704320_preload_common.js32
-rw-r--r--dom/base/test/file_bug704320_preload_reuse.html31
-rw-r--r--dom/base/test/file_bug704320_redirect.html10
-rw-r--r--dom/base/test/file_bug707142_baseline.json1
-rw-r--r--dom/base/test/file_bug707142_bom.json1
-rw-r--r--dom/base/test/file_bug707142_utf-16.jsonbin0 -> 32 bytes
-rw-r--r--dom/base/test/file_bug708620-2.html4
-rw-r--r--dom/base/test/file_bug708620.html7
-rw-r--r--dom/base/test/file_bug753278.html1
-rw-r--r--dom/base/test/file_bug769117.html16
-rw-r--r--dom/base/test/file_bug782342.txt1
-rw-r--r--dom/base/test/file_bug787778.sjs7
-rw-r--r--dom/base/test/file_bug869432.eventsource4
-rw-r--r--dom/base/test/file_bug869432.eventsource^headers^3
-rw-r--r--dom/base/test/file_bug902350.html19
-rw-r--r--dom/base/test/file_bug902350_frame.html14
-rw-r--r--dom/base/test/file_bug907892.html12
-rw-r--r--dom/base/test/file_bug945152.jarbin0 -> 92275 bytes
-rw-r--r--dom/base/test/file_bug945152_worker.js99
-rw-r--r--dom/base/test/file_change_policy_redirect.html10
-rw-r--r--dom/base/test/file_current_inner_window.html24
-rw-r--r--dom/base/test/file_delazification_strategy.html10
-rw-r--r--dom/base/test/file_delazification_strategy.js91
-rw-r--r--dom/base/test/file_domwindowutils_animation.html217
-rw-r--r--dom/base/test/file_domwindowutils_dynamic_toolbar.html23
-rw-r--r--dom/base/test/file_empty.html1
-rw-r--r--dom/base/test/file_explicit_user_agent.sjs6
-rw-r--r--dom/base/test/file_external_script.html11
-rw-r--r--dom/base/test/file_external_script.xhtml11
-rw-r--r--dom/base/test/file_focus_design_mode_inner.html32
-rw-r--r--dom/base/test/file_focus_display_none_xorigin_iframe_inner.html15
-rw-r--r--dom/base/test/file_focus_shadow_dom.html999
-rw-r--r--dom/base/test/file_general_document.html10
-rw-r--r--dom/base/test/file_history_document_open.html1
-rw-r--r--dom/base/test/file_htmlserializer_1.html44
-rw-r--r--dom/base/test/file_htmlserializer_1_bodyonly.html43
-rw-r--r--dom/base/test/file_htmlserializer_1_format.html57
-rw-r--r--dom/base/test/file_htmlserializer_1_linebreak.html47
-rw-r--r--dom/base/test/file_htmlserializer_1_links.html47
-rw-r--r--dom/base/test/file_htmlserializer_1_nested_body.html47
-rw-r--r--dom/base/test/file_htmlserializer_1_no_body.html5
-rw-r--r--dom/base/test/file_htmlserializer_1_noflag.html47
-rw-r--r--dom/base/test/file_htmlserializer_1_noformatpre.html51
-rw-r--r--dom/base/test/file_htmlserializer_1_raw.html45
-rw-r--r--dom/base/test/file_htmlserializer_1_sibling_body.html47
-rw-r--r--dom/base/test/file_htmlserializer_1_sibling_body_only_body.html43
-rw-r--r--dom/base/test/file_htmlserializer_1_wrap.html52
-rw-r--r--dom/base/test/file_htmlserializer_2.html22
-rw-r--r--dom/base/test/file_htmlserializer_2_basic.html24
-rw-r--r--dom/base/test/file_htmlserializer_ipv6.html5
-rw-r--r--dom/base/test/file_htmlserializer_ipv6_out.html6
-rw-r--r--dom/base/test/file_inline_script.html11
-rw-r--r--dom/base/test/file_inline_script.xhtml11
-rw-r--r--dom/base/test/file_js_cache.html10
-rw-r--r--dom/base/test/file_js_cache.js5
-rw-r--r--dom/base/test/file_js_cache_module.html13
-rw-r--r--dom/base/test/file_js_cache_save_after_load.html10
-rw-r--r--dom/base/test/file_js_cache_save_after_load.js15
-rw-r--r--dom/base/test/file_js_cache_syntax_error.html10
-rw-r--r--dom/base/test/file_js_cache_syntax_error.js1
-rw-r--r--dom/base/test/file_js_cache_with_sri.html12
-rw-r--r--dom/base/test/file_location_href_unknown_protocol.html15
-rw-r--r--dom/base/test/file_lock_orientation_with_pending_fullscreen.html22
-rw-r--r--dom/base/test/file_messagemanager_unload.html6
-rw-r--r--dom/base/test/file_module_js_cache.html10
-rw-r--r--dom/base/test/file_module_js_cache.js6
-rw-r--r--dom/base/test/file_module_js_cache_no_module.html10
-rw-r--r--dom/base/test/file_module_js_cache_with_sri.html12
-rw-r--r--dom/base/test/file_mozfiledataurl_img.jpgbin0 -> 2711 bytes
-rw-r--r--dom/base/test/file_navigator_resolve_identity_xrays.xhtml29
-rw-r--r--dom/base/test/file_receiveMessage.html13
-rw-r--r--dom/base/test/file_restrictedEventSource.sjs69
-rw-r--r--dom/base/test/file_sandbox_and_document_uri.html34
-rw-r--r--dom/base/test/file_script.js1
-rw-r--r--dom/base/test/file_script_module_dynamic_and_element.html10
-rw-r--r--dom/base/test/file_script_module_dynamic_and_element.js19
-rw-r--r--dom/base/test/file_script_module_dynamic_and_element_imported_1.js6
-rw-r--r--dom/base/test/file_script_module_dynamic_and_element_imported_2.js1
-rw-r--r--dom/base/test/file_script_module_dynamic_and_element_imported_3.js1
-rw-r--r--dom/base/test/file_script_module_dynamic_and_static.html10
-rw-r--r--dom/base/test/file_script_module_dynamic_and_static.js10
-rw-r--r--dom/base/test/file_script_module_dynamic_and_static_imported_1.js4
-rw-r--r--dom/base/test/file_script_module_dynamic_and_static_imported_2.js4
-rw-r--r--dom/base/test/file_script_module_dynamic_and_static_imported_3.js1
-rw-r--r--dom/base/test/file_script_module_dynamic_import.html10
-rw-r--r--dom/base/test/file_script_module_dynamic_import.js4
-rw-r--r--dom/base/test/file_script_module_dynamic_import_imported.js1
-rw-r--r--dom/base/test/file_script_module_element_and_dynamic.html10
-rw-r--r--dom/base/test/file_script_module_element_and_dynamic.js10
-rw-r--r--dom/base/test/file_script_module_element_and_dynamic_imported_1.js12
-rw-r--r--dom/base/test/file_script_module_element_and_dynamic_imported_2.js1
-rw-r--r--dom/base/test/file_script_module_element_and_dynamic_imported_3.js1
-rw-r--r--dom/base/test/file_script_module_element_and_import.html10
-rw-r--r--dom/base/test/file_script_module_element_and_import.js8
-rw-r--r--dom/base/test/file_script_module_element_and_import_imported_1.js12
-rw-r--r--dom/base/test/file_script_module_element_and_import_imported_2.js1
-rw-r--r--dom/base/test/file_script_module_element_and_import_imported_3.js1
-rw-r--r--dom/base/test/file_script_module_frames_dynamic.html24
-rw-r--r--dom/base/test/file_script_module_frames_dynamic_load.html19
-rw-r--r--dom/base/test/file_script_module_frames_dynamic_load.js4
-rw-r--r--dom/base/test/file_script_module_frames_dynamic_save.html19
-rw-r--r--dom/base/test/file_script_module_frames_dynamic_save.js4
-rw-r--r--dom/base/test/file_script_module_frames_dynamic_shared.js1
-rw-r--r--dom/base/test/file_script_module_frames_element.html24
-rw-r--r--dom/base/test/file_script_module_frames_element_load.html19
-rw-r--r--dom/base/test/file_script_module_frames_element_save.html19
-rw-r--r--dom/base/test/file_script_module_frames_element_shared.js1
-rw-r--r--dom/base/test/file_script_module_frames_import.html24
-rw-r--r--dom/base/test/file_script_module_frames_import_load.html19
-rw-r--r--dom/base/test/file_script_module_frames_import_load.js4
-rw-r--r--dom/base/test/file_script_module_frames_import_save.html19
-rw-r--r--dom/base/test/file_script_module_frames_import_save.js4
-rw-r--r--dom/base/test/file_script_module_frames_import_shared.js1
-rw-r--r--dom/base/test/file_script_module_frames_relay.js22
-rw-r--r--dom/base/test/file_script_module_import.html10
-rw-r--r--dom/base/test/file_script_module_import.js4
-rw-r--r--dom/base/test/file_script_module_import_and_element.html10
-rw-r--r--dom/base/test/file_script_module_import_and_element.js17
-rw-r--r--dom/base/test/file_script_module_import_and_element_imported_1.js6
-rw-r--r--dom/base/test/file_script_module_import_and_element_imported_2.js1
-rw-r--r--dom/base/test/file_script_module_import_and_element_imported_3.js1
-rw-r--r--dom/base/test/file_script_module_import_imported.js1
-rw-r--r--dom/base/test/file_script_module_import_multi.html10
-rw-r--r--dom/base/test/file_script_module_import_multi.js6
-rw-r--r--dom/base/test/file_script_module_import_multi_elems.html10
-rw-r--r--dom/base/test/file_script_module_import_multi_elems_1.js14
-rw-r--r--dom/base/test/file_script_module_import_multi_elems_2.js6
-rw-r--r--dom/base/test/file_script_module_import_multi_elems_imported_once_1.js1
-rw-r--r--dom/base/test/file_script_module_import_multi_elems_imported_once_2.js1
-rw-r--r--dom/base/test/file_script_module_import_multi_elems_imported_once_3.js1
-rw-r--r--dom/base/test/file_script_module_import_multi_elems_imported_twice.js3
-rw-r--r--dom/base/test/file_script_module_import_multi_imported_once.js4
-rw-r--r--dom/base/test/file_script_module_import_multi_imported_twice.js1
-rw-r--r--dom/base/test/file_script_module_single.html10
-rw-r--r--dom/base/test/file_script_module_single.js8
-rw-r--r--dom/base/test/file_script_module_sri_basic.html11
-rw-r--r--dom/base/test/file_script_module_sri_basic.js1
-rw-r--r--dom/base/test/file_script_module_sri_basic_prep.html11
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem.html12
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem.js4
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem_imported.js3
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem_nopreload.html10
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem_nopreload.js20
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem_nopreload_imported.js3
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem_nopreload_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_dynamic_elem_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_elem_dynamic.html12
-rw-r--r--dom/base/test/file_script_module_sri_elem_dynamic.js4
-rw-r--r--dom/base/test/file_script_module_sri_elem_dynamic_imported.js3
-rw-r--r--dom/base/test/file_script_module_sri_elem_dynamic_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_elem_elem_1.html12
-rw-r--r--dom/base/test/file_script_module_sri_elem_elem_1.js1
-rw-r--r--dom/base/test/file_script_module_sri_elem_elem_1_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_elem_elem_2.html12
-rw-r--r--dom/base/test/file_script_module_sri_elem_elem_2.js1
-rw-r--r--dom/base/test/file_script_module_sri_elem_elem_2_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_elem_import.html12
-rw-r--r--dom/base/test/file_script_module_sri_elem_import.js4
-rw-r--r--dom/base/test/file_script_module_sri_elem_import_imported.js3
-rw-r--r--dom/base/test/file_script_module_sri_elem_import_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_fallback.html11
-rw-r--r--dom/base/test/file_script_module_sri_fallback.js1
-rw-r--r--dom/base/test/file_script_module_sri_fallback_failure.html15
-rw-r--r--dom/base/test/file_script_module_sri_fallback_failure.js1
-rw-r--r--dom/base/test/file_script_module_sri_fallback_failure_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_fallback_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_import_elem.html12
-rw-r--r--dom/base/test/file_script_module_sri_import_elem.js4
-rw-r--r--dom/base/test/file_script_module_sri_import_elem_imported.js3
-rw-r--r--dom/base/test/file_script_module_sri_import_elem_nopreload.html10
-rw-r--r--dom/base/test/file_script_module_sri_import_elem_nopreload.js18
-rw-r--r--dom/base/test/file_script_module_sri_import_elem_nopreload_imported.js3
-rw-r--r--dom/base/test/file_script_module_sri_import_elem_nopreload_prep.html10
-rw-r--r--dom/base/test/file_script_module_sri_import_elem_prep.html10
-rw-r--r--dom/base/test/file_script_module_static_and_dynamic.html10
-rw-r--r--dom/base/test/file_script_module_static_and_dynamic.js8
-rw-r--r--dom/base/test/file_script_module_static_and_dynamic_imported_1.js4
-rw-r--r--dom/base/test/file_script_module_static_and_dynamic_imported_2.js6
-rw-r--r--dom/base/test/file_script_module_static_and_dynamic_imported_3.js1
-rw-r--r--dom/base/test/file_serializer_noscript.html1
-rw-r--r--dom/base/test/file_setname.html8
-rw-r--r--dom/base/test/file_settimeout_inner.html1
-rw-r--r--dom/base/test/file_suppressed_events_and_scrolling.html30
-rw-r--r--dom/base/test/file_suppressed_events_inner.html16
-rw-r--r--dom/base/test/file_suppressed_events_middle.html10
-rw-r--r--dom/base/test/file_suppressed_events_top.html79
-rw-r--r--dom/base/test/file_suppressed_events_top_modalstate.html79
-rw-r--r--dom/base/test/file_suppressed_events_top_xhr.html82
-rw-r--r--dom/base/test/file_timer_flood.html19
-rw-r--r--dom/base/test/file_title.xhtml1
-rw-r--r--dom/base/test/file_toScreenRect.html48
-rw-r--r--dom/base/test/file_use_counter_bfcache.html38
-rw-r--r--dom/base/test/file_use_counter_bfcache_helper.html40
-rw-r--r--dom/base/test/file_use_counter_outer.html17
-rw-r--r--dom/base/test/file_use_counter_outer_display_none.html16
-rw-r--r--dom/base/test/file_use_counter_style.html14
-rw-r--r--dom/base/test/file_use_counter_svg_currentScale.svg17
-rw-r--r--dom/base/test/file_use_counter_svg_fill_pattern.svg16
-rw-r--r--dom/base/test/file_use_counter_svg_fill_pattern_data.svg13
-rw-r--r--dom/base/test/file_use_counter_svg_fill_pattern_definition.svg12
-rw-r--r--dom/base/test/file_use_counter_svg_fill_pattern_internal.svg24
-rw-r--r--dom/base/test/file_use_counter_svg_getElementById.svg22
-rw-r--r--dom/base/test/file_viewport_metrics_on_landscape_content.html65
-rw-r--r--dom/base/test/file_viewport_scroll_quirks.html1
-rw-r--r--dom/base/test/file_viewport_scroll_xml.xml1
-rw-r--r--dom/base/test/file_webaudio_startstop.html36
-rw-r--r--dom/base/test/file_window_close.html68
-rw-r--r--dom/base/test/file_window_close_2.html4
-rw-r--r--dom/base/test/file_window_focus_by_close_and_open.html13
-rw-r--r--dom/base/test/file_x-frame-options_main.html44
-rw-r--r--dom/base/test/file_x-frame-options_page.sjs67
-rw-r--r--dom/base/test/file_xhtmlserializer_1.xhtml60
-rw-r--r--dom/base/test/file_xhtmlserializer_1_bodyonly.xhtml56
-rw-r--r--dom/base/test/file_xhtmlserializer_1_format.xhtml71
-rw-r--r--dom/base/test/file_xhtmlserializer_1_linebreak.xhtml65
-rw-r--r--dom/base/test/file_xhtmlserializer_1_links.xhtml65
-rw-r--r--dom/base/test/file_xhtmlserializer_1_nested_body.xhtml65
-rw-r--r--dom/base/test/file_xhtmlserializer_1_no_body.xhtml10
-rw-r--r--dom/base/test/file_xhtmlserializer_1_noflag.xhtml65
-rw-r--r--dom/base/test/file_xhtmlserializer_1_noformatpre.xhtml69
-rw-r--r--dom/base/test/file_xhtmlserializer_1_raw.xhtml60
-rw-r--r--dom/base/test/file_xhtmlserializer_1_sibling_body.xhtml65
-rw-r--r--dom/base/test/file_xhtmlserializer_1_sibling_body_only_body.xhtml56
-rw-r--r--dom/base/test/file_xhtmlserializer_1_wrap.xhtml70
-rw-r--r--dom/base/test/file_xhtmlserializer_2.xhtml30
-rw-r--r--dom/base/test/file_xhtmlserializer_2_basic.xhtml31
-rw-r--r--dom/base/test/file_xhtmlserializer_2_enthtml.xhtml55
-rw-r--r--dom/base/test/file_xhtmlserializer_2_entw3c.xhtml55
-rw-r--r--dom/base/test/file_xhtmlserializer_2_latin1.xhtml41
-rw-r--r--dom/base/test/file_youtube_flash_embed.html65
-rw-r--r--dom/base/test/fmm/browser.ini1
-rw-r--r--dom/base/test/fmm/browser_frame_message_manager_cache.js23
-rw-r--r--dom/base/test/forRemoval.resource24
-rw-r--r--dom/base/test/forRemoval.resource^headers^3
-rw-r--r--dom/base/test/formReset.html15
-rw-r--r--dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml108
-rw-r--r--dom/base/test/fullscreen/browser.ini40
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-api-keys.js218
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js127
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js128
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js141
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js122
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-document-mutation.js118
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-navigation-history.js100
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-navigation-race.js162
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-navigation.js142
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-newtab.js91
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-sizemode.js225
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js101
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-tab-close.js65
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen-window-open-race.js73
-rw-r--r--dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js215
-rw-r--r--dom/base/test/fullscreen/chrome.ini10
-rw-r--r--dom/base/test/fullscreen/dummy_page.html10
-rw-r--r--dom/base/test/fullscreen/file_MozDomFullscreen.html8
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-api-keys.html41
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-api-race.html8
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-api.html340
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-async.html50
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-backdrop.html107
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html22
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-bug-1798219.html14
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-denied-inner.html24
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-denied.html171
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html58
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-esc-exit.html63
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-event-order.html50
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html34
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-featurePolicy.html90
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-focus-inner.html24
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-focus.html67
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-hidden.html56
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-iframe-inner.html5
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-iframe-middle.html5
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-iframe-top.html5
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-lenient-setters.html61
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-multiple-inner.html25
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-multiple.html67
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-navigation.html52
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-nested.html130
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-newtab.html4
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-prefixed.html153
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-resize.html39
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-rollback.html140
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-scrollbar.html147
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-selector.html183
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-shadowdom.html52
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-single.html78
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-sub-iframe.html53
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-svg-element.html49
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-table.html52
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-top-layer.html160
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-utils.js87
-rw-r--r--dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html36
-rw-r--r--dom/base/test/fullscreen/file_fullscreen_meta_viewport.html12
-rw-r--r--dom/base/test/fullscreen/fullscreen.xhtml27
-rw-r--r--dom/base/test/fullscreen/fullscreen_helpers.js174
-rw-r--r--dom/base/test/fullscreen/head.js65
-rw-r--r--dom/base/test/fullscreen/mochitest.ini51
-rw-r--r--dom/base/test/fullscreen/moz.build17
-rw-r--r--dom/base/test/fullscreen/test_MozDomFullscreen_event.xhtml46
-rw-r--r--dom/base/test/fullscreen/test_fullscreen-api-race.html177
-rw-r--r--dom/base/test/fullscreen/test_fullscreen-api-rapid-cycle.html167
-rw-r--r--dom/base/test/fullscreen/test_fullscreen-api.html150
-rw-r--r--dom/base/test/fullscreen/test_fullscreen.xhtml37
-rw-r--r--dom/base/test/fullscreen/test_fullscreen_meta_viewport.html33
-rw-r--r--dom/base/test/fullscreen/test_fullscreen_modal.html68
-rw-r--r--dom/base/test/green.pngbin0 -> 255 bytes
-rw-r--r--dom/base/test/gtest/TestContentUtils.cpp146
-rw-r--r--dom/base/test/gtest/TestMimeType.cpp816
-rw-r--r--dom/base/test/gtest/TestParser.cpp52
-rw-r--r--dom/base/test/gtest/TestPlainTextSerializer.cpp309
-rw-r--r--dom/base/test/gtest/TestScheduler.cpp348
-rw-r--r--dom/base/test/gtest/TestXMLSerializerNoBreakLink.cpp69
-rw-r--r--dom/base/test/gtest/TestXPathGenerator.cpp150
-rw-r--r--dom/base/test/gtest/moz.build21
-rw-r--r--dom/base/test/head.js15
-rw-r--r--dom/base/test/iframe1_bug1640766.html20
-rw-r--r--dom/base/test/iframe1_bug426646.html1
-rw-r--r--dom/base/test/iframe1_bug431701.html1
-rw-r--r--dom/base/test/iframe2_bug1640766.html10
-rw-r--r--dom/base/test/iframe2_bug426646.html1
-rw-r--r--dom/base/test/iframe2_bug431701.html1
-rw-r--r--dom/base/test/iframe3_bug431701.html1
-rw-r--r--dom/base/test/iframe4_bug431701.xml1
-rw-r--r--dom/base/test/iframe5_bug431701.xml1
-rw-r--r--dom/base/test/iframe6_bug431701.xml1
-rw-r--r--dom/base/test/iframe7_bug431701.xml1
-rw-r--r--dom/base/test/iframe_bug962251.html25
-rw-r--r--dom/base/test/iframe_bug976673.html26
-rw-r--r--dom/base/test/iframe_main_bug1022229.html33
-rw-r--r--dom/base/test/iframe_meta_refresh.sjs92
-rw-r--r--dom/base/test/iframe_postMessage_solidus.html15
-rw-r--r--dom/base/test/iframe_postMessages.html14
-rw-r--r--dom/base/test/iframe_sandbox_bug1022229.html13
-rw-r--r--dom/base/test/iframe_shared_compartment2a.html2
-rw-r--r--dom/base/test/iframe_shared_compartment2b.html3
-rw-r--r--dom/base/test/intersectionobserver_cross_domain_iframe.html24
-rw-r--r--dom/base/test/intersectionobserver_iframe.html17
-rw-r--r--dom/base/test/intersectionobserver_window.html46
-rw-r--r--dom/base/test/invalid_accesscontrol.resource7
-rw-r--r--dom/base/test/invalid_accesscontrol.resource^headers^4
-rw-r--r--dom/base/test/jsmodules/.eslintrc.js7
-rw-r--r--dom/base/test/jsmodules/chrome.ini53
-rw-r--r--dom/base/test/jsmodules/iframe_extractIntroType.html14
-rw-r--r--dom/base/test/jsmodules/importmaps/chrome.ini29
-rw-r--r--dom/base/test/jsmodules/importmaps/external_importMap.js5
-rw-r--r--dom/base/test/jsmodules/importmaps/insert_a_base_element.js4
-rw-r--r--dom/base/test/jsmodules/importmaps/module_simpleExport.js1
-rw-r--r--dom/base/test/jsmodules/importmaps/module_simpleImportMap.js2
-rw-r--r--dom/base/test/jsmodules/importmaps/module_simpleImportMap_dir.js2
-rw-r--r--dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap.js2
-rw-r--r--dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap_https.js2
-rw-r--r--dom/base/test/jsmodules/importmaps/module_sortedImportMap.js4
-rw-r--r--dom/base/test/jsmodules/importmaps/moz.build7
-rw-r--r--dom/base/test/jsmodules/importmaps/scope1/module_simpleExport.js1
-rw-r--r--dom/base/test/jsmodules/importmaps/scope1/module_simpleImportMap.js2
-rw-r--r--dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleExport.js1
-rw-r--r--dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleImportMap.js2
-rw-r--r--dom/base/test/jsmodules/importmaps/test_dynamic_import_reject_importMap.html46
-rw-r--r--dom/base/test/jsmodules/importmaps/test_externalImportMap.html43
-rw-r--r--dom/base/test/jsmodules/importmaps/test_import_meta_resolve_importMap.html49
-rw-r--r--dom/base/test/jsmodules/importmaps/test_inline_module_reject_importMap.html61
-rw-r--r--dom/base/test/jsmodules/importmaps/test_load_importMap_with_base.html51
-rw-r--r--dom/base/test/jsmodules/importmaps/test_load_importMap_with_base2.html51
-rw-r--r--dom/base/test/jsmodules/importmaps/test_module_script_reject_importMap.html45
-rw-r--r--dom/base/test/jsmodules/importmaps/test_parse_importMap_failed.html40
-rw-r--r--dom/base/test/jsmodules/importmaps/test_reject_multiple_importMaps.html64
-rw-r--r--dom/base/test/jsmodules/importmaps/test_simpleImportMap.html62
-rw-r--r--dom/base/test/jsmodules/importmaps/test_sortedImportMap.html62
-rw-r--r--dom/base/test/jsmodules/module_badImport.js1
-rw-r--r--dom/base/test/jsmodules/module_badSyntax.js3
-rw-r--r--dom/base/test/jsmodules/module_cyclic1.js8
-rw-r--r--dom/base/test/jsmodules/module_cyclic2.js8
-rw-r--r--dom/base/test/jsmodules/module_cyclic3.js8
-rw-r--r--dom/base/test/jsmodules/module_extractIntroType.js5
-rw-r--r--dom/base/test/jsmodules/module_large1.js78
-rw-r--r--dom/base/test/jsmodules/module_large2.js78
-rw-r--r--dom/base/test/jsmodules/module_large3.js78
-rw-r--r--dom/base/test/jsmodules/module_missingImport.js1
-rw-r--r--dom/base/test/jsmodules/module_multiImports.js4
-rw-r--r--dom/base/test/jsmodules/module_multiLargeImports.js4
-rw-r--r--dom/base/test/jsmodules/module_setRan.js2
-rw-r--r--dom/base/test/jsmodules/module_simple1.js1
-rw-r--r--dom/base/test/jsmodules/module_simple2.js1
-rw-r--r--dom/base/test/jsmodules/module_simple3.js1
-rw-r--r--dom/base/test/jsmodules/module_simpleExport.js1
-rw-r--r--dom/base/test/jsmodules/module_simpleImport.js2
-rw-r--r--dom/base/test/jsmodules/module_testSyntax.js3
-rw-r--r--dom/base/test/jsmodules/moz.build7
-rw-r--r--dom/base/test/jsmodules/script_simple2.js1
-rw-r--r--dom/base/test/jsmodules/test_asyncInlineModules.html36
-rw-r--r--dom/base/test/jsmodules/test_cyclicImport.html18
-rw-r--r--dom/base/test/jsmodules/test_dynamicImportErrorMessage.html16
-rw-r--r--dom/base/test/jsmodules/test_importIntroType.html22
-rw-r--r--dom/base/test/jsmodules/test_importNotFound.html27
-rw-r--r--dom/base/test/jsmodules/test_importResolveFailed.html21
-rw-r--r--dom/base/test/jsmodules/test_import_meta_resolve.html65
-rw-r--r--dom/base/test/jsmodules/test_importedModuleMemoization.html30
-rw-r--r--dom/base/test/jsmodules/test_linkErrorInCommon1.html32
-rw-r--r--dom/base/test/jsmodules/test_linkErrorInCommon2.html32
-rw-r--r--dom/base/test/jsmodules/test_moduleNotFound.html24
-rw-r--r--dom/base/test/jsmodules/test_moduleParsedAsModule.html23
-rw-r--r--dom/base/test/jsmodules/test_moduleScriptsRun.html19
-rw-r--r--dom/base/test/jsmodules/test_multiAsyncImports.html30
-rw-r--r--dom/base/test/jsmodules/test_multiModuleImports.html28
-rw-r--r--dom/base/test/jsmodules/test_multiModuleLargeImports.html28
-rw-r--r--dom/base/test/jsmodules/test_multiTopLevelImports.html30
-rw-r--r--dom/base/test/jsmodules/test_multiTopLevelLargeImports.html30
-rw-r--r--dom/base/test/jsmodules/test_scriptInsertedModule.html20
-rw-r--r--dom/base/test/jsmodules/test_scriptModuleOrder.html30
-rw-r--r--dom/base/test/jsmodules/test_scriptNotParsedAsModule.html23
-rw-r--r--dom/base/test/jsmodules/test_simpleImport.html16
-rw-r--r--dom/base/test/jsmodules/test_syntaxError.html30
-rw-r--r--dom/base/test/jsmodules/test_syntaxErrorAsync.html30
-rw-r--r--dom/base/test/jsmodules/test_syntaxErrorInline.html34
-rw-r--r--dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html34
-rw-r--r--dom/base/test/jsmodules/test_topLevelIntroType.html21
-rw-r--r--dom/base/test/jsmodules/test_toplevelModuleMemoization.html30
-rw-r--r--dom/base/test/jsmodules/test_typeAttrCaseInsensitive.html19
-rw-r--r--dom/base/test/meta_viewport/mochitest.ini54
-rw-r--r--dom/base/test/meta_viewport/moz.build9
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport0.html41
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport1.html41
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport2.html41
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport3.html43
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport4.html42
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport5.html24
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport6.html47
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport7.html71
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport8.html27
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_height.html24
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_width.html24
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_height_and_initial_scale_1.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_device_height.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_initial_scale_1.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_0_5.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_1.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width.html24
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width_and_fixed_height.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_change_content_among_multiple.html52
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_change_name.html47
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_change_name_among_multiple.html44
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_device_width.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_0_5.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_2.html31
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_empty_content_and_valid_content_tags.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_fit.html34
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_fit_multiple.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_fixed_width_and_zero_display_width.html29
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_initial_scale_0_5.html33
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_initial_scale_2.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_initial_scale_with_trailing_characters.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_insert_before_existing_tag.html32
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0.html28
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0_5.html29
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_2.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_multiple_tags.html28
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_negative_height.html27
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_no_height.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_valid_height.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_no_content_and_valid_content_tags.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_no_width_and_negative_height.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_no_width_and_valid_height.html25
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_remove_node.html34
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_remove_node_from_multiple.html44
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_removing_content_attribute.html33
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_replace_content.html39
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_tiny_display_size.html28
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_negative_height.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_no_height.html26
-rw-r--r--dom/base/test/meta_viewport/test_meta_viewport_width_with_trailing_characters.html26
-rw-r--r--dom/base/test/meta_viewport/viewport_helpers.js44
-rw-r--r--dom/base/test/mochitest.ini1111
-rw-r--r--dom/base/test/moz.build44
-rw-r--r--dom/base/test/object_bug353334.html1
-rw-r--r--dom/base/test/object_bug455472.html1
-rw-r--r--dom/base/test/red.pngbin0 -> 87 bytes
-rw-r--r--dom/base/test/referrerHelper.js343
-rw-r--r--dom/base/test/referrer_change_server.sjs166
-rw-r--r--dom/base/test/referrer_header.sjs6
-rw-r--r--dom/base/test/referrer_helper.js133
-rw-r--r--dom/base/test/referrer_testserver.sjs693
-rw-r--r--dom/base/test/reftest/mixed-bmp-png.icobin0 -> 17542 bytes
-rw-r--r--dom/base/test/reftest/reftest.list7
-rw-r--r--dom/base/test/reftest/test_bug1525662-ref.html15
-rw-r--r--dom/base/test/reftest/test_bug1525662.txt7
-rw-r--r--dom/base/test/reftest/test_bug920877-ref.html20
-rw-r--r--dom/base/test/reftest/test_bug920877.html38
-rw-r--r--dom/base/test/reftest/test_xmlPrettyPrint_csp-ref.xml4
-rw-r--r--dom/base/test/reftest/test_xmlPrettyPrint_csp.xml4
-rw-r--r--dom/base/test/reftest/test_xmlPrettyPrint_csp.xml^headers^1
-rw-r--r--dom/base/test/script-1_bug597345.sjs22
-rw-r--r--dom/base/test/script-2_bug597345.js1
-rw-r--r--dom/base/test/script_bug1238440.js33
-rw-r--r--dom/base/test/script_bug602838.sjs43
-rw-r--r--dom/base/test/script_postmessages_fileList.js26
-rw-r--r--dom/base/test/send_gzip_content.sjs46
-rw-r--r--dom/base/test/slow.sjs15
-rw-r--r--dom/base/test/somedatas.resource16
-rw-r--r--dom/base/test/somedatas.resource^headers^3
-rw-r--r--dom/base/test/test_EventSource_redirects.html53
-rw-r--r--dom/base/test/test_Image_constructor.html32
-rw-r--r--dom/base/test/test_NodeIterator_basics_filters.xhtml178
-rw-r--r--dom/base/test/test_NodeIterator_mutations_1.xhtml204
-rw-r--r--dom/base/test/test_NodeIterator_mutations_2.html112
-rw-r--r--dom/base/test/test_NodeIterator_mutations_3.html160
-rw-r--r--dom/base/test/test_anchor_area_referrer.html127
-rw-r--r--dom/base/test/test_anchor_area_referrer_changing.html66
-rw-r--r--dom/base/test/test_anchor_area_referrer_invalid.html74
-rw-r--r--dom/base/test/test_anchor_area_referrer_rel.html50
-rw-r--r--dom/base/test/test_anchor_target_blank_referrer.html134
-rw-r--r--dom/base/test/test_anonymousContent_api.html56
-rw-r--r--dom/base/test/test_anonymousContent_append_after_reflow.html40
-rw-r--r--dom/base/test/test_anonymousContent_canvas.html59
-rw-r--r--dom/base/test/test_anonymousContent_insert.html45
-rw-r--r--dom/base/test/test_anonymousContent_manipulate_content.html74
-rw-r--r--dom/base/test/test_anonymousContent_set_style.html35
-rw-r--r--dom/base/test/test_anonymousContent_style_csp.html28
-rw-r--r--dom/base/test/test_anonymousContent_style_csp.html^headers^1
-rw-r--r--dom/base/test/test_anonymousContent_xul_window.xhtml23
-rw-r--r--dom/base/test/test_appname_override.html26
-rw-r--r--dom/base/test/test_async_setTimeout_stack.html60
-rw-r--r--dom/base/test/test_async_setTimeout_stack_across_globals.html60
-rw-r--r--dom/base/test/test_base.xhtml39
-rw-r--r--dom/base/test/test_blockParsing.html134
-rw-r--r--dom/base/test/test_blocking_image.html94
-rw-r--r--dom/base/test/test_bug1008126.html62
-rw-r--r--dom/base/test/test_bug1016960.html30
-rw-r--r--dom/base/test/test_bug1022229.html33
-rw-r--r--dom/base/test/test_bug1025933.html41
-rw-r--r--dom/base/test/test_bug1037687.html32
-rw-r--r--dom/base/test/test_bug1037687_subframe.html46
-rw-r--r--dom/base/test/test_bug1043106.html44
-rw-r--r--dom/base/test/test_bug1057176.html32
-rw-r--r--dom/base/test/test_bug1060938.html44
-rw-r--r--dom/base/test/test_bug1064481.html24
-rw-r--r--dom/base/test/test_bug1070015.html53
-rw-r--r--dom/base/test/test_bug1075702.html77
-rw-r--r--dom/base/test/test_bug1091883.html89
-rw-r--r--dom/base/test/test_bug1100912.html35
-rw-r--r--dom/base/test/test_bug1101364.html93
-rw-r--r--dom/base/test/test_bug1118689.html40
-rw-r--r--dom/base/test/test_bug1120222.html31
-rw-r--r--dom/base/test/test_bug1126851.html44
-rw-r--r--dom/base/test/test_bug116083.html120
-rw-r--r--dom/base/test/test_bug1163743.html44
-rw-r--r--dom/base/test/test_bug1165501.html51
-rw-r--r--dom/base/test/test_bug1187157.html30
-rw-r--r--dom/base/test/test_bug1198095.html71
-rw-r--r--dom/base/test/test_bug1222633.html112
-rw-r--r--dom/base/test/test_bug1222633_link_update.html129
-rw-r--r--dom/base/test/test_bug1238440.html88
-rw-r--r--dom/base/test/test_bug1250148.html64
-rw-r--r--dom/base/test/test_bug1259588.html13
-rw-r--r--dom/base/test/test_bug1268962.html104
-rw-r--r--dom/base/test/test_bug1274806.html31
-rw-r--r--dom/base/test/test_bug1281963.html56
-rw-r--r--dom/base/test/test_bug1295852.html23
-rw-r--r--dom/base/test/test_bug1307730.html44
-rw-r--r--dom/base/test/test_bug1308069.html87
-rw-r--r--dom/base/test/test_bug1314032.html38
-rw-r--r--dom/base/test/test_bug1318303.html49
-rw-r--r--dom/base/test/test_bug1375050.html33
-rw-r--r--dom/base/test/test_bug1381710.html40
-rw-r--r--dom/base/test/test_bug1399605.html32
-rw-r--r--dom/base/test/test_bug1404385.html31
-rw-r--r--dom/base/test/test_bug1406102.html41
-rw-r--r--dom/base/test/test_bug1421568.html48
-rw-r--r--dom/base/test/test_bug1433073.html89
-rw-r--r--dom/base/test/test_bug1472427.html89
-rw-r--r--dom/base/test/test_bug1499169.html32
-rw-r--r--dom/base/test/test_bug1576154.html36
-rw-r--r--dom/base/test/test_bug1632975.html54
-rw-r--r--dom/base/test/test_bug1639328.html68
-rw-r--r--dom/base/test/test_bug1640766.html67
-rw-r--r--dom/base/test/test_bug1648887.html34
-rw-r--r--dom/base/test/test_bug166235.html156
-rw-r--r--dom/base/test/test_bug1667316.html153
-rw-r--r--dom/base/test/test_bug1730284.html71
-rw-r--r--dom/base/test/test_bug1739957.html40
-rw-r--r--dom/base/test/test_bug1784187.html38
-rw-r--r--dom/base/test/test_bug1799354.html77
-rw-r--r--dom/base/test/test_bug199959.html39
-rw-r--r--dom/base/test/test_bug218236.html139
-rw-r--r--dom/base/test/test_bug218277.html28
-rw-r--r--dom/base/test/test_bug238409.html45
-rw-r--r--dom/base/test/test_bug254337.html42
-rw-r--r--dom/base/test/test_bug270145.xhtml51
-rw-r--r--dom/base/test/test_bug276037-1.html105
-rw-r--r--dom/base/test/test_bug276037-2.xhtml106
-rw-r--r--dom/base/test/test_bug282547.html104
-rw-r--r--dom/base/test/test_bug28293.html86
-rw-r--r--dom/base/test/test_bug28293.xhtml87
-rw-r--r--dom/base/test/test_bug298064.html32
-rw-r--r--dom/base/test/test_bug300992.html45
-rw-r--r--dom/base/test/test_bug311681.xml103
-rw-r--r--dom/base/test/test_bug313646.html62
-rw-r--r--dom/base/test/test_bug320799.html74
-rw-r--r--dom/base/test/test_bug322317.html33
-rw-r--r--dom/base/test/test_bug326337.html35
-rw-r--r--dom/base/test/test_bug331959.html151
-rw-r--r--dom/base/test/test_bug333064.html59
-rw-r--r--dom/base/test/test_bug333198.html84
-rw-r--r--dom/base/test/test_bug333673.html30
-rw-r--r--dom/base/test/test_bug337631.html99
-rw-r--r--dom/base/test/test_bug338541.xhtml49
-rw-r--r--dom/base/test/test_bug338583.html665
-rw-r--r--dom/base/test/test_bug338679.html82
-rw-r--r--dom/base/test/test_bug339494.html59
-rw-r--r--dom/base/test/test_bug339494.xhtml58
-rw-r--r--dom/base/test/test_bug343596.html51
-rw-r--r--dom/base/test/test_bug345339.html93
-rw-r--r--dom/base/test/test_bug346485.html77
-rw-r--r--dom/base/test/test_bug352728.html122
-rw-r--r--dom/base/test/test_bug352728.xhtml188
-rw-r--r--dom/base/test/test_bug353334.html67
-rw-r--r--dom/base/test/test_bug355026.html29
-rw-r--r--dom/base/test/test_bug357450.html41
-rw-r--r--dom/base/test/test_bug357450.xhtml39
-rw-r--r--dom/base/test/test_bug357450_svg.xhtml46
-rw-r--r--dom/base/test/test_bug357509.html36
-rw-r--r--dom/base/test/test_bug358660.html37
-rw-r--r--dom/base/test/test_bug362391.xhtml75
-rw-r--r--dom/base/test/test_bug364092.xhtml46
-rw-r--r--dom/base/test/test_bug364413.xhtml48
-rw-r--r--dom/base/test/test_bug366944.html49
-rw-r--r--dom/base/test/test_bug366946.html79
-rw-r--r--dom/base/test/test_bug367164.html47
-rw-r--r--dom/base/test/test_bug368972.html120
-rw-r--r--dom/base/test/test_bug371576-2.html32
-rw-r--r--dom/base/test/test_bug371576-3.html29
-rw-r--r--dom/base/test/test_bug371576-4.html21
-rw-r--r--dom/base/test/test_bug371576-5.html36
-rw-r--r--dom/base/test/test_bug372086.html96
-rw-r--r--dom/base/test/test_bug372964-2.html58
-rw-r--r--dom/base/test/test_bug372964.html144
-rw-r--r--dom/base/test/test_bug373181.xhtml17
-rw-r--r--dom/base/test/test_bug375314-2.html151
-rw-r--r--dom/base/test/test_bug375314.html160
-rw-r--r--dom/base/test/test_bug378969.html47
-rw-r--r--dom/base/test/test_bug380418.html34
-rw-r--r--dom/base/test/test_bug380418.html^headers^4
-rw-r--r--dom/base/test/test_bug382113.html35
-rw-r--r--dom/base/test/test_bug382871.html46
-rw-r--r--dom/base/test/test_bug384003.xhtml84
-rw-r--r--dom/base/test/test_bug390219.html38
-rw-r--r--dom/base/test/test_bug390735.html28
-rw-r--r--dom/base/test/test_bug392318.html44
-rw-r--r--dom/base/test/test_bug392511.html53
-rw-r--r--dom/base/test/test_bug393968.html41
-rw-r--r--dom/base/test/test_bug395915.html43
-rw-r--r--dom/base/test/test_bug397234.html42
-rw-r--r--dom/base/test/test_bug398243.html56
-rw-r--r--dom/base/test/test_bug401662.html51
-rw-r--r--dom/base/test/test_bug402150.html24
-rw-r--r--dom/base/test/test_bug402150.html^headers^1
-rw-r--r--dom/base/test/test_bug403841.html29
-rw-r--r--dom/base/test/test_bug403852.html66
-rw-r--r--dom/base/test/test_bug403868.xml85
-rw-r--r--dom/base/test/test_bug405182.html47
-rw-r--r--dom/base/test/test_bug409380.html378
-rw-r--r--dom/base/test/test_bug410229.html108
-rw-r--r--dom/base/test/test_bug413974.html35
-rw-r--r--dom/base/test/test_bug414190.html70
-rw-r--r--dom/base/test/test_bug415860.html240
-rw-r--r--dom/base/test/test_bug416317-1.html32
-rw-r--r--dom/base/test/test_bug416317-2.html32
-rw-r--r--dom/base/test/test_bug416383.html43
-rw-r--r--dom/base/test/test_bug417255.html60
-rw-r--r--dom/base/test/test_bug417384.html50
-rw-r--r--dom/base/test/test_bug418214.html105
-rw-r--r--dom/base/test/test_bug418986-1.html24
-rw-r--r--dom/base/test/test_bug419132.html48
-rw-r--r--dom/base/test/test_bug419527.xhtml68
-rw-r--r--dom/base/test/test_bug420609.xhtml34
-rw-r--r--dom/base/test/test_bug420700.html35
-rw-r--r--dom/base/test/test_bug421602.html53
-rw-r--r--dom/base/test/test_bug422403-1.html204
-rw-r--r--dom/base/test/test_bug422403-2.xhtml296
-rw-r--r--dom/base/test/test_bug422537.html55
-rw-r--r--dom/base/test/test_bug424212.html35
-rw-r--r--dom/base/test/test_bug424359-1.html213
-rw-r--r--dom/base/test/test_bug424359-2.html301
-rw-r--r--dom/base/test/test_bug426308.html42
-rw-r--r--dom/base/test/test_bug426646.html41
-rw-r--r--dom/base/test/test_bug428847.html33
-rw-r--r--dom/base/test/test_bug431082.html51
-rw-r--r--dom/base/test/test_bug431701.html119
-rw-r--r--dom/base/test/test_bug431833.html51
-rw-r--r--dom/base/test/test_bug433533.html300
-rw-r--r--dom/base/test/test_bug433662.html31
-rw-r--r--dom/base/test/test_bug435425.html430
-rw-r--r--dom/base/test/test_bug444322.html2588
-rw-r--r--dom/base/test/test_bug444546.html160
-rw-r--r--dom/base/test/test_bug444722.html65
-rw-r--r--dom/base/test/test_bug448993.html46
-rw-r--r--dom/base/test/test_bug450160.html100
-rw-r--r--dom/base/test/test_bug451376.html86
-rw-r--r--dom/base/test/test_bug453521.html36
-rw-r--r--dom/base/test/test_bug453736.html58
-rw-r--r--dom/base/test/test_bug454325.html147
-rw-r--r--dom/base/test/test_bug454326.html135
-rw-r--r--dom/base/test/test_bug455472.html41
-rw-r--r--dom/base/test/test_bug455629.html63
-rw-r--r--dom/base/test/test_bug456262.html39
-rw-r--r--dom/base/test/test_bug457746.html38
-rw-r--r--dom/base/test/test_bug459424.html31
-rw-r--r--dom/base/test/test_bug461555.html46
-rw-r--r--dom/base/test/test_bug461735.html50
-rw-r--r--dom/base/test/test_bug465767.html42
-rw-r--r--dom/base/test/test_bug466080.html150
-rw-r--r--dom/base/test/test_bug466409.html34
-rw-r--r--dom/base/test/test_bug466751.xhtml40
-rw-r--r--dom/base/test/test_bug469020.html128
-rw-r--r--dom/base/test/test_bug469304.html187
-rw-r--r--dom/base/test/test_bug473162-1.html30
-rw-r--r--dom/base/test/test_bug473162-2.html33
-rw-r--r--dom/base/test/test_bug475156.html301
-rw-r--r--dom/base/test/test_bug482935.html72
-rw-r--r--dom/base/test/test_bug484396.html48
-rw-r--r--dom/base/test/test_bug493881.html31
-rw-r--r--dom/base/test/test_bug493881.js100
-rw-r--r--dom/base/test/test_bug498240.html254
-rw-r--r--dom/base/test/test_bug498433.html104
-rw-r--r--dom/base/test/test_bug498897.html97
-rw-r--r--dom/base/test/test_bug499656.html57
-rw-r--r--dom/base/test/test_bug499656.xhtml57
-rw-r--r--dom/base/test/test_bug500937.html54
-rw-r--r--dom/base/test/test_bug503473.html37
-rw-r--r--dom/base/test/test_bug503481.html69
-rw-r--r--dom/base/test/test_bug503481b.html22
-rw-r--r--dom/base/test/test_bug51034.html42
-rw-r--r--dom/base/test/test_bug513194.html28
-rw-r--r--dom/base/test/test_bug5141.html30
-rw-r--r--dom/base/test/test_bug514487.html49
-rw-r--r--dom/base/test/test_bug515401.html141
-rw-r--r--dom/base/test/test_bug518104.html41
-rw-r--r--dom/base/test/test_bug527896.html61
-rw-r--r--dom/base/test/test_bug540854.html47
-rw-r--r--dom/base/test/test_bug541937.html118
-rw-r--r--dom/base/test/test_bug544642.html42
-rw-r--r--dom/base/test/test_bug545644.html42
-rw-r--r--dom/base/test/test_bug545644.xhtml49
-rw-r--r--dom/base/test/test_bug548463.html66
-rw-r--r--dom/base/test/test_bug553896.xhtml69
-rw-r--r--dom/base/test/test_bug557892.html34
-rw-r--r--dom/base/test/test_bug558726.html40
-rw-r--r--dom/base/test/test_bug559526.html93
-rw-r--r--dom/base/test/test_bug560780.html99
-rw-r--r--dom/base/test/test_bug562137.html32
-rw-r--r--dom/base/test/test_bug562169-1.html44
-rw-r--r--dom/base/test/test_bug562169-2.html29
-rw-r--r--dom/base/test/test_bug562652.html51
-rw-r--r--dom/base/test/test_bug564047.html31
-rw-r--r--dom/base/test/test_bug564863-2.xhtml159
-rw-r--r--dom/base/test/test_bug564863.xhtml305
-rw-r--r--dom/base/test/test_bug567350.html24
-rw-r--r--dom/base/test/test_bug574596.html94
-rw-r--r--dom/base/test/test_bug578096.html49
-rw-r--r--dom/base/test/test_bug585978.html38
-rw-r--r--dom/base/test/test_bug587931.html102
-rw-r--r--dom/base/test/test_bug588990.html332
-rw-r--r--dom/base/test/test_bug590812.html48
-rw-r--r--dom/base/test/test_bug590870.html44
-rw-r--r--dom/base/test/test_bug592366.html59
-rw-r--r--dom/base/test/test_bug592829.html40
-rw-r--r--dom/base/test/test_bug597345.html27
-rw-r--r--dom/base/test/test_bug599295.html47
-rw-r--r--dom/base/test/test_bug599588.html39
-rw-r--r--dom/base/test/test_bug601803.html35
-rw-r--r--dom/base/test/test_bug602838.html68
-rw-r--r--dom/base/test/test_bug604592.html37
-rw-r--r--dom/base/test/test_bug604660.html77
-rw-r--r--dom/base/test/test_bug605982.html34
-rw-r--r--dom/base/test/test_bug606729.html52
-rw-r--r--dom/base/test/test_bug614058.html29
-rw-r--r--dom/base/test/test_bug622088.html96
-rw-r--r--dom/base/test/test_bug622117.html49
-rw-r--r--dom/base/test/test_bug622246.html49
-rw-r--r--dom/base/test/test_bug625722.html39
-rw-r--r--dom/base/test/test_bug626262.html54
-rw-r--r--dom/base/test/test_bug628938.html239
-rw-r--r--dom/base/test/test_bug631615.html39
-rw-r--r--dom/base/test/test_bug638112.html46
-rw-r--r--dom/base/test/test_bug647518.html45
-rw-r--r--dom/base/test/test_bug650001.html30
-rw-r--r--dom/base/test/test_bug650776.html109
-rw-r--r--dom/base/test/test_bug650784.html37
-rw-r--r--dom/base/test/test_bug656283.html58
-rw-r--r--dom/base/test/test_bug664916.html39
-rw-r--r--dom/base/test/test_bug666604.html149
-rw-r--r--dom/base/test/test_bug675121.html45
-rw-r--r--dom/base/test/test_bug675166.html57
-rw-r--r--dom/base/test/test_bug682463.html156
-rw-r--r--dom/base/test/test_bug682554.html30
-rw-r--r--dom/base/test/test_bug682592.html178
-rw-r--r--dom/base/test/test_bug684671.html45
-rw-r--r--dom/base/test/test_bug685798.html45
-rw-r--r--dom/base/test/test_bug686449.xhtml79
-rw-r--r--dom/base/test/test_bug687859.html33
-rw-r--r--dom/base/test/test_bug690056.html54
-rw-r--r--dom/base/test/test_bug692434.html44
-rw-r--r--dom/base/test/test_bug693615.html41
-rw-r--r--dom/base/test/test_bug693875.html34
-rw-r--r--dom/base/test/test_bug694754.xhtml70
-rw-r--r--dom/base/test/test_bug696301-1.html78
-rw-r--r--dom/base/test/test_bug696301-2.html80
-rw-r--r--dom/base/test/test_bug698381.html55
-rw-r--r--dom/base/test/test_bug698384.html61
-rw-r--r--dom/base/test/test_bug704063.html56
-rw-r--r--dom/base/test/test_bug704320-1.html90
-rw-r--r--dom/base/test/test_bug704320-2.html90
-rw-r--r--dom/base/test/test_bug704320_policyset.html104
-rw-r--r--dom/base/test/test_bug704320_policyset2.html45
-rw-r--r--dom/base/test/test_bug704320_preload.html136
-rw-r--r--dom/base/test/test_bug707142.html51
-rw-r--r--dom/base/test/test_bug708620.html41
-rw-r--r--dom/base/test/test_bug711047.html16
-rw-r--r--dom/base/test/test_bug711180.html25
-rw-r--r--dom/base/test/test_bug719533.html27
-rw-r--r--dom/base/test/test_bug726364.html48
-rw-r--r--dom/base/test/test_bug737087.html37
-rw-r--r--dom/base/test/test_bug737565.html64
-rw-r--r--dom/base/test/test_bug737612.html29
-rw-r--r--dom/base/test/test_bug738108.html39
-rw-r--r--dom/base/test/test_bug744830.html132
-rw-r--r--dom/base/test/test_bug749367.html29
-rw-r--r--dom/base/test/test_bug750096.html44
-rw-r--r--dom/base/test/test_bug753278.html46
-rw-r--r--dom/base/test/test_bug761120.html41
-rw-r--r--dom/base/test/test_bug769117.html55
-rw-r--r--dom/base/test/test_bug782342.html85
-rw-r--r--dom/base/test/test_bug787778.html25
-rw-r--r--dom/base/test/test_bug789315.html49
-rw-r--r--dom/base/test/test_bug789856.html42
-rw-r--r--dom/base/test/test_bug809003.html47
-rw-r--r--dom/base/test/test_bug810494.html46
-rw-r--r--dom/base/test/test_bug811701.html48
-rw-r--r--dom/base/test/test_bug811701.xhtml52
-rw-r--r--dom/base/test/test_bug813919.html46
-rw-r--r--dom/base/test/test_bug814576.html41
-rw-r--r--dom/base/test/test_bug819051.html59
-rw-r--r--dom/base/test/test_bug820909.html87
-rw-r--r--dom/base/test/test_bug864595.html34
-rw-r--r--dom/base/test/test_bug868999.html39
-rw-r--r--dom/base/test/test_bug869000.html37
-rw-r--r--dom/base/test/test_bug869002.html32
-rw-r--r--dom/base/test/test_bug869006.html37
-rw-r--r--dom/base/test/test_bug876282.html45
-rw-r--r--dom/base/test/test_bug891952.html61
-rw-r--r--dom/base/test/test_bug894874.html45
-rw-r--r--dom/base/test/test_bug895974.html69
-rw-r--r--dom/base/test/test_bug907892.html49
-rw-r--r--dom/base/test/test_bug913761.html40
-rw-r--r--dom/base/test/test_bug922681.html113
-rw-r--r--dom/base/test/test_bug927196.html56
-rw-r--r--dom/base/test/test_bug945152.html58
-rw-r--r--dom/base/test/test_bug962251.html244
-rw-r--r--dom/base/test/test_bug976673.html105
-rw-r--r--dom/base/test/test_bug982153.html29
-rw-r--r--dom/base/test/test_bug999456.html32
-rw-r--r--dom/base/test/test_caretPositionFromPoint.html131
-rw-r--r--dom/base/test/test_change_policy.html134
-rw-r--r--dom/base/test/test_clearTimeoutIntervalNoArg.html14
-rw-r--r--dom/base/test/test_clipboard_nbsp.html116
-rw-r--r--dom/base/test/test_constructor-assignment.html61
-rw-r--r--dom/base/test/test_constructor.html61
-rw-r--r--dom/base/test/test_content_iterator_post_order.html875
-rw-r--r--dom/base/test/test_content_iterator_pre_order.html869
-rw-r--r--dom/base/test/test_content_iterator_subtree.html690
-rw-r--r--dom/base/test/test_copyimage.html87
-rw-r--r--dom/base/test/test_copypaste.html125
-rw-r--r--dom/base/test/test_copypaste.xhtml112
-rw-r--r--dom/base/test/test_copypaste_disabled.html116
-rw-r--r--dom/base/test/test_createHTMLDocument.html52
-rw-r--r--dom/base/test/test_current_inner_window.html61
-rw-r--r--dom/base/test/test_custom_element.html29
-rw-r--r--dom/base/test/test_custom_element_reflector.html27
-rw-r--r--dom/base/test/test_data_uri.html189
-rw-r--r--dom/base/test/test_delazification_strategy.html175
-rw-r--r--dom/base/test/test_document.all_iteration.html11
-rw-r--r--dom/base/test/test_document.all_unqualified.html35
-rw-r--r--dom/base/test/test_document_constructor.html31
-rw-r--r--dom/base/test/test_document_importNode_document.html32
-rw-r--r--dom/base/test/test_document_wireframe.html354
-rw-r--r--dom/base/test/test_domparser_null_char.html27
-rw-r--r--dom/base/test/test_domparsing.html84
-rw-r--r--dom/base/test/test_domrequest.html233
-rw-r--r--dom/base/test/test_domrequesthelper.xhtml547
-rw-r--r--dom/base/test/test_domwindowutils.html128
-rw-r--r--dom/base/test/test_element.matches.html28
-rw-r--r--dom/base/test/test_elementTraversal.html111
-rw-r--r--dom/base/test/test_element_closest.html84
-rw-r--r--dom/base/test/test_embed_xorigin_document.html103
-rw-r--r--dom/base/test/test_encodeToStringWithMaxLength.html60
-rw-r--r--dom/base/test/test_encodeToStringWithRequiresReinitAfterOutput.html87
-rw-r--r--dom/base/test/test_eventsource_event_listener_leaks.html40
-rw-r--r--dom/base/test/test_eventsourceservice_basic.html69
-rw-r--r--dom/base/test/test_eventsourceservice_reconnect_error.html72
-rw-r--r--dom/base/test/test_eventsourceservice_status_error.html67
-rw-r--r--dom/base/test/test_eventsourceservice_worker.html61
-rw-r--r--dom/base/test/test_explicit_user_agent.html64
-rw-r--r--dom/base/test/test_find.html204
-rw-r--r--dom/base/test/test_find_bug1601118.html61
-rw-r--r--dom/base/test/test_find_bug1654683.html30
-rw-r--r--dom/base/test/test_find_nac.html13
-rw-r--r--dom/base/test/test_focus_design_mode.html62
-rw-r--r--dom/base/test/test_focus_display_none_xorigin_iframe.html134
-rw-r--r--dom/base/test/test_focus_keyboard_event.html48
-rw-r--r--dom/base/test/test_focus_scroll_padding_tab.html74
-rw-r--r--dom/base/test/test_focus_scrollable_fieldset.html60
-rw-r--r--dom/base/test/test_focus_scrollable_input.html56
-rw-r--r--dom/base/test/test_focus_shadow_dom.html36
-rw-r--r--dom/base/test/test_focus_shadow_dom_root.html41
-rw-r--r--dom/base/test/test_fragment_sanitization.xhtml98
-rw-r--r--dom/base/test/test_getAttribute_after_createAttribute.html15
-rw-r--r--dom/base/test/test_getElementById.html58
-rw-r--r--dom/base/test/test_getLastOverWindowPointerLocationInCSSPixels.html83
-rw-r--r--dom/base/test/test_getTranslationNodes.html225
-rw-r--r--dom/base/test/test_getTranslationNodes_limit.html31
-rw-r--r--dom/base/test/test_gsp-qualified.html38
-rw-r--r--dom/base/test/test_gsp-quirks.html27
-rw-r--r--dom/base/test/test_gsp-standards.html27
-rw-r--r--dom/base/test/test_history_document_open.html37
-rw-r--r--dom/base/test/test_history_state_null.html25
-rw-r--r--dom/base/test/test_html_colors_quirks.html711
-rw-r--r--dom/base/test/test_html_colors_standards.html712
-rw-r--r--dom/base/test/test_htmlcopyencoder.html195
-rw-r--r--dom/base/test/test_htmlcopyencoder.xhtml179
-rw-r--r--dom/base/test/test_iframe_event_listener_leaks.html41
-rw-r--r--dom/base/test/test_iframe_referrer.html107
-rw-r--r--dom/base/test/test_iframe_referrer_changing.html50
-rw-r--r--dom/base/test/test_iframe_referrer_invalid.html81
-rw-r--r--dom/base/test/test_innersize_scrollport.html38
-rw-r--r--dom/base/test/test_input_vsync_alignment_inner_event_loop.html49
-rw-r--r--dom/base/test/test_input_vsync_alignment_input_while_vsync.html47
-rw-r--r--dom/base/test/test_input_vsync_alignment_lower_than_normal.html51
-rw-r--r--dom/base/test/test_integer_attr_with_leading_zero.html64
-rw-r--r--dom/base/test/test_intersectionobservers.html1221
-rw-r--r--dom/base/test/test_link_prefetch.html220
-rw-r--r--dom/base/test/test_link_preload.html220
-rw-r--r--dom/base/test/test_link_stylesheet.html221
-rw-r--r--dom/base/test/test_location_href_unknown_protocol.html27
-rw-r--r--dom/base/test/test_lock_orientation_after_fullscreen.html58
-rw-r--r--dom/base/test/test_lock_orientation_with_pending_fullscreen.html126
-rw-r--r--dom/base/test/test_messagePort.html114
-rw-r--r--dom/base/test/test_messagemanager_send_principal.html108
-rw-r--r--dom/base/test/test_meta_refresh_referrer.html98
-rw-r--r--dom/base/test/test_mozMatchesSelector.html14
-rw-r--r--dom/base/test/test_mutationobservers.html862
-rw-r--r--dom/base/test/test_named_frames.html38
-rw-r--r--dom/base/test/test_navigatorPrefOverride.html54
-rw-r--r--dom/base/test/test_navigator_cookieEnabled.html124
-rw-r--r--dom/base/test/test_navigator_hardwareConcurrency.html42
-rw-r--r--dom/base/test/test_navigator_language.html213
-rw-r--r--dom/base/test/test_navigator_resolve_identity_xrays.xhtml39
-rw-r--r--dom/base/test/test_nested_event_loop_spin_and_idle_tasks.html34
-rw-r--r--dom/base/test/test_nodelist_holes.html42
-rw-r--r--dom/base/test/test_openDialogChromeOnly.html38
-rw-r--r--dom/base/test/test_open_null_features.html54
-rw-r--r--dom/base/test/test_pasting_svg_image.html99
-rw-r--r--dom/base/test/test_pdf_print.html62
-rw-r--r--dom/base/test/test_plugin_freezing.html68
-rw-r--r--dom/base/test/test_postMessage_originAttributes.html53
-rw-r--r--dom/base/test/test_postMessage_solidus.html93
-rw-r--r--dom/base/test/test_postMessages_broadcastChannel.html167
-rw-r--r--dom/base/test/test_postMessages_messagePort.html114
-rw-r--r--dom/base/test/test_postMessages_window.html124
-rw-r--r--dom/base/test/test_postMessages_workers.html111
-rw-r--r--dom/base/test/test_processing_instruction_update_stylesheet.xhtml46
-rw-r--r--dom/base/test/test_progress_events_for_gzip_data.html44
-rw-r--r--dom/base/test/test_pushState_structuredclone.html51
-rw-r--r--dom/base/test/test_range_bounds.html305
-rw-r--r--dom/base/test/test_reentrant_flush.html60
-rw-r--r--dom/base/test/test_root_iframe.html27
-rw-r--r--dom/base/test/test_sandbox_and_document_uri.html31
-rw-r--r--dom/base/test/test_sandboxed_blob_uri.html22
-rw-r--r--dom/base/test/test_sanitize_xhr.html35
-rw-r--r--dom/base/test/test_screen_orientation.html86
-rw-r--r--dom/base/test/test_script_loader_crossorigin_data_url.html38
-rw-r--r--dom/base/test/test_script_loader_js_cache.html264
-rw-r--r--dom/base/test/test_script_loader_js_cache_frames.html202
-rw-r--r--dom/base/test/test_script_loader_js_cache_module.html537
-rw-r--r--dom/base/test/test_script_loader_js_cache_module_sri.html425
-rw-r--r--dom/base/test/test_sendQueryContentAndSelectionSetEvent.html253
-rw-r--r--dom/base/test/test_sendSelectionSetEvent_with_same_range.html100
-rw-r--r--dom/base/test/test_serializer_noscript.html38
-rw-r--r--dom/base/test/test_setInterval_from_start.html57
-rw-r--r--dom/base/test/test_setInterval_uncatchable_exception.html55
-rw-r--r--dom/base/test/test_setTimeoutWith0.html22
-rw-r--r--dom/base/test/test_settimeout_extra_arguments.html12
-rw-r--r--dom/base/test/test_settimeout_inner.html59
-rw-r--r--dom/base/test/test_setting_opener.html125
-rw-r--r--dom/base/test/test_shared_compartment1.html77
-rw-r--r--dom/base/test/test_shared_compartment2.html47
-rw-r--r--dom/base/test/test_structuredclone_backref.html32
-rw-r--r--dom/base/test/test_structuredclone_error.html23
-rw-r--r--dom/base/test/test_style_cssText.html85
-rw-r--r--dom/base/test/test_suppressed_events_and_scrolling.html47
-rw-r--r--dom/base/test/test_suppressed_events_nested_iframe.html71
-rw-r--r--dom/base/test/test_suppressed_microtasks.html62
-rw-r--r--dom/base/test/test_text_wholeText.html232
-rw-r--r--dom/base/test/test_textnode_normalize_in_selection.html201
-rw-r--r--dom/base/test/test_textnode_split_in_selection.html221
-rw-r--r--dom/base/test/test_timeout_clamp.html163
-rw-r--r--dom/base/test/test_timer_flood.html118
-rw-r--r--dom/base/test/test_title.html52
-rw-r--r--dom/base/test/test_toScreenRect.html9
-rw-r--r--dom/base/test/test_treewalker_nextsibling.xml96
-rw-r--r--dom/base/test/test_urgent_start.html269
-rw-r--r--dom/base/test/test_user_select.html357
-rw-r--r--dom/base/test/test_viewport_metrics_on_landscape_content.html20
-rw-r--r--dom/base/test/test_viewport_scroll.html89
-rw-r--r--dom/base/test/test_viewsource_forbidden_in_object.html62
-rw-r--r--dom/base/test/test_w3element_traversal.html148
-rw-r--r--dom/base/test/test_w3element_traversal.xhtml149
-rw-r--r--dom/base/test/test_w3element_traversal_svg.html107
-rw-r--r--dom/base/test/test_warning_for_blocked_cross_site_request.html129
-rw-r--r--dom/base/test/test_window_close.html93
-rw-r--r--dom/base/test/test_window_constructor.html36
-rw-r--r--dom/base/test/test_window_content.html28
-rw-r--r--dom/base/test/test_window_cross_origin_props.html101
-rw-r--r--dom/base/test/test_window_define_nonconfigurable.html115
-rw-r--r--dom/base/test/test_window_define_symbol.html29
-rw-r--r--dom/base/test/test_window_element_enumeration.html70
-rw-r--r--dom/base/test/test_window_enumeration.html33
-rw-r--r--dom/base/test/test_window_extensible.html46
-rw-r--r--dom/base/test/test_window_focus_by_close_and_open.html34
-rw-r--r--dom/base/test/test_window_indexing.html139
-rw-r--r--dom/base/test/test_window_keys.html28
-rw-r--r--dom/base/test/test_window_named_frame_enumeration.html96
-rw-r--r--dom/base/test/test_window_own_props.html29
-rw-r--r--dom/base/test/test_window_proto.html17
-rw-r--r--dom/base/test/test_writable-replaceable.html49
-rw-r--r--dom/base/test/test_x-frame-options.html195
-rw-r--r--dom/base/test/test_youtube_flash_embed.html32
-rw-r--r--dom/base/test/unit/1_original.xml3
-rw-r--r--dom/base/test/unit/1_result.xml3
-rw-r--r--dom/base/test/unit/2_original.xml13
-rw-r--r--dom/base/test/unit/2_result_1.xml13
-rw-r--r--dom/base/test/unit/2_result_2.xml14
-rw-r--r--dom/base/test/unit/2_result_3.xml23
-rw-r--r--dom/base/test/unit/2_result_4.xml21
-rw-r--r--dom/base/test/unit/3_original.xml4
-rw-r--r--dom/base/test/unit/3_result.xml7
-rw-r--r--dom/base/test/unit/3_result_2.xml7
-rw-r--r--dom/base/test/unit/4_original.xml32
-rw-r--r--dom/base/test/unit/4_result_1.xml32
-rw-r--r--dom/base/test/unit/4_result_2.xml7
-rw-r--r--dom/base/test/unit/4_result_3.xml4
-rw-r--r--dom/base/test/unit/4_result_4.xml4
-rw-r--r--dom/base/test/unit/4_result_5.xml46
-rw-r--r--dom/base/test/unit/4_result_6.xml48
-rw-r--r--dom/base/test/unit/empty_document.xml3
-rw-r--r--dom/base/test/unit/head_utilities.js69
-rw-r--r--dom/base/test/unit/head_xml.js152
-rw-r--r--dom/base/test/unit/isequalnode_data.xml150
-rw-r--r--dom/base/test/unit/nodelist_data_1.xml58
-rw-r--r--dom/base/test/unit/nodelist_data_2.xhtml45
-rw-r--r--dom/base/test/unit/test_blockParsing.js113
-rw-r--r--dom/base/test/unit/test_bug553888.js57
-rw-r--r--dom/base/test/unit/test_bug737966.js16
-rw-r--r--dom/base/test/unit/test_cancelPrefetch.js149
-rw-r--r--dom/base/test/unit/test_chromeutils_base64.js140
-rw-r--r--dom/base/test/unit/test_chromeutils_getXPCOMErrorName.js40
-rw-r--r--dom/base/test/unit/test_chromeutils_shallowclone.js60
-rw-r--r--dom/base/test/unit/test_delete_range.xml125
-rw-r--r--dom/base/test/unit/test_error_codes.js64
-rw-r--r--dom/base/test/unit/test_generate_xpath.js85
-rw-r--r--dom/base/test/unit/test_htmlserializer.js70
-rw-r--r--dom/base/test/unit/test_isequalnode.js390
-rw-r--r--dom/base/test/unit/test_js_dev_error_interceptor.js53
-rw-r--r--dom/base/test/unit/test_nodelist.js345
-rw-r--r--dom/base/test/unit/test_normalize.js100
-rw-r--r--dom/base/test/unit/test_range.js465
-rw-r--r--dom/base/test/unit/test_serializers_entities.js99
-rw-r--r--dom/base/test/unit/test_serializers_entities_in_attr.js108
-rw-r--r--dom/base/test/unit/test_structuredcloneholder.js159
-rw-r--r--dom/base/test/unit/test_thirdpartyutil.js99
-rw-r--r--dom/base/test/unit/test_treewalker.js23
-rw-r--r--dom/base/test/unit/test_xhr_document.js45
-rw-r--r--dom/base/test/unit/test_xhr_origin_attributes.js53
-rw-r--r--dom/base/test/unit/test_xhr_standalone.js19
-rw-r--r--dom/base/test/unit/test_xml_parser.js48
-rw-r--r--dom/base/test/unit/test_xml_serializer.js421
-rw-r--r--dom/base/test/unit/test_xmlserializer.js179
-rw-r--r--dom/base/test/unit/xpcshell.ini70
-rw-r--r--dom/base/test/unit_ipc/test_bug553888_wrap.js3
-rw-r--r--dom/base/test/unit_ipc/test_xhr_document_ipc.js3
-rw-r--r--dom/base/test/unit_ipc/xpcshell.ini11
-rw-r--r--dom/base/test/useractivation/file_clipboard_common.js505
-rw-r--r--dom/base/test/useractivation/file_empty.html0
-rw-r--r--dom/base/test/useractivation/file_iframe_check_user_activation.html22
-rw-r--r--dom/base/test/useractivation/file_iframe_consume_user_activation.html15
-rw-r--r--dom/base/test/useractivation/file_iframe_user_activated.html14
-rw-r--r--dom/base/test/useractivation/file_useractivation_sandbox_transient_popup.html20
-rw-r--r--dom/base/test/useractivation/mochitest.ini23
-rw-r--r--dom/base/test/useractivation/moz.build9
-rw-r--r--dom/base/test/useractivation/test_clipboard_editor.html31
-rw-r--r--dom/base/test/useractivation/test_clipboard_noeditor.html29
-rw-r--r--dom/base/test/useractivation/test_popup_blocker_async_callback.html83
-rw-r--r--dom/base/test/useractivation/test_popup_blocker_mouse_event.html98
-rw-r--r--dom/base/test/useractivation/test_popup_blocker_pointer_event.html122
-rw-r--r--dom/base/test/useractivation/test_useractivation_has_been_activated.html115
-rw-r--r--dom/base/test/useractivation/test_useractivation_key_events.html91
-rw-r--r--dom/base/test/useractivation/test_useractivation_sandbox_transient.html90
-rw-r--r--dom/base/test/useractivation/test_useractivation_scrollbar.html135
-rw-r--r--dom/base/test/useractivation/test_useractivation_transient.html155
-rw-r--r--dom/base/test/useractivation/test_useractivation_transient_consuming.html151
-rw-r--r--dom/base/test/variable_style_sheet.sjs18
-rw-r--r--dom/base/test/w3element_traversal.svg70
-rw-r--r--dom/base/test/wholeTexty-helper.xml6
-rw-r--r--dom/base/test/worker_postMessages.js73
1382 files changed, 94517 insertions, 0 deletions
diff --git a/dom/base/test/.eslintrc.js b/dom/base/test/.eslintrc.js
new file mode 100644
index 0000000000..43ad70dd5e
--- /dev/null
+++ b/dom/base/test/.eslintrc.js
@@ -0,0 +1,12 @@
+"use strict";
+
+module.exports = {
+ overrides: [
+ {
+ files: ["file_module_js_cache.js", "file_script_module_*.js"],
+ parserOptions: {
+ sourceType: "module",
+ },
+ },
+ ],
+};
diff --git a/dom/base/test/345339_iframe.html b/dom/base/test/345339_iframe.html
new file mode 100644
index 0000000000..f4b2ecd13b
--- /dev/null
+++ b/dom/base/test/345339_iframe.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/REC-html401-19991224/strict.dtd">
+<html>
+ <head>
+ <title>Form Elements</title>
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ </head>
+ <body>
+ <p>
+ <select id="select">
+ <option value="Mozilla">Mozilla</option>
+ <option value="Firefox">Firefox</option>
+ </select>
+ <form name="radioform" id="radioform">
+ <input type="radio" id="radio1" name="answer" value="Yes"
+ checked="checked" />
+ <input type="radio" id="radio2" name="answer" value="No" />
+ </form>
+
+ <input type="password" id="password" />
+
+ <input type="hidden" id="hidden" />
+
+ <input id="passwordToggle" />
+
+ <input type="file" id="file" />
+ </p>
+ </body>
+</html>
diff --git a/dom/base/test/Ahem.ttf b/dom/base/test/Ahem.ttf
new file mode 100644
index 0000000000..ac81cb0316
--- /dev/null
+++ b/dom/base/test/Ahem.ttf
Binary files differ
diff --git a/dom/base/test/FAIL.html b/dom/base/test/FAIL.html
new file mode 100644
index 0000000000..94e1707e85
--- /dev/null
+++ b/dom/base/test/FAIL.html
@@ -0,0 +1 @@
+FAIL
diff --git a/dom/base/test/PASS.html b/dom/base/test/PASS.html
new file mode 100644
index 0000000000..7ef22e9a43
--- /dev/null
+++ b/dom/base/test/PASS.html
@@ -0,0 +1 @@
+PASS
diff --git a/dom/base/test/accesscontrol.resource b/dom/base/test/accesscontrol.resource
new file mode 100644
index 0000000000..aca66f6f8d
--- /dev/null
+++ b/dom/base/test/accesscontrol.resource
@@ -0,0 +1,7 @@
+:this file must be enconded in utf8
+:and its Content-Type must be equal to text/event-stream
+
+event: message
+data: 1
+
+
diff --git a/dom/base/test/accesscontrol.resource^headers^ b/dom/base/test/accesscontrol.resource^headers^
new file mode 100644
index 0000000000..75f1f88972
--- /dev/null
+++ b/dom/base/test/accesscontrol.resource^headers^
@@ -0,0 +1,5 @@
+Access-Control-Allow-Origin: http://mochi.test:8888
+Access-Control-Allow-Credentials: true
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate
+
diff --git a/dom/base/test/audio.ogg b/dom/base/test/audio.ogg
new file mode 100644
index 0000000000..bed764fbf1
--- /dev/null
+++ b/dom/base/test/audio.ogg
Binary files differ
diff --git a/dom/base/test/badContentType.eventsource b/dom/base/test/badContentType.eventsource
new file mode 100644
index 0000000000..c9d0739e18
--- /dev/null
+++ b/dom/base/test/badContentType.eventsource
@@ -0,0 +1,5 @@
+retry:500
+event: message
+data: 1
+
+
diff --git a/dom/base/test/badContentType.eventsource^headers^ b/dom/base/test/badContentType.eventsource^headers^
new file mode 100644
index 0000000000..a1f9e38d90
--- /dev/null
+++ b/dom/base/test/badContentType.eventsource^headers^
@@ -0,0 +1 @@
+Content-Type: text/plain
diff --git a/dom/base/test/badHTTPResponseCode.eventsource b/dom/base/test/badHTTPResponseCode.eventsource
new file mode 100644
index 0000000000..c9d0739e18
--- /dev/null
+++ b/dom/base/test/badHTTPResponseCode.eventsource
@@ -0,0 +1,5 @@
+retry:500
+event: message
+data: 1
+
+
diff --git a/dom/base/test/badHTTPResponseCode.eventsource^headers^ b/dom/base/test/badHTTPResponseCode.eventsource^headers^
new file mode 100644
index 0000000000..545a9a201c
--- /dev/null
+++ b/dom/base/test/badHTTPResponseCode.eventsource^headers^
@@ -0,0 +1,2 @@
+HTTP 404 Not Found
+Content-Type: text/event-stream
diff --git a/dom/base/test/badMessageEvent.eventsource b/dom/base/test/badMessageEvent.eventsource
new file mode 100644
index 0000000000..0c635f0b57
--- /dev/null
+++ b/dom/base/test/badMessageEvent.eventsource
@@ -0,0 +1,4 @@
+retry:500
+event: message
+
+
diff --git a/dom/base/test/badMessageEvent.eventsource^headers^ b/dom/base/test/badMessageEvent.eventsource^headers^
new file mode 100644
index 0000000000..9bb8badcad
--- /dev/null
+++ b/dom/base/test/badMessageEvent.eventsource^headers^
@@ -0,0 +1 @@
+Content-Type: text/event-stream
diff --git a/dom/base/test/badMessageEvent2.eventsource b/dom/base/test/badMessageEvent2.eventsource
new file mode 100644
index 0000000000..ad6fa694f4
--- /dev/null
+++ b/dom/base/test/badMessageEvent2.eventsource
@@ -0,0 +1,5 @@
+retry:500
+data: ok
+
+id: invalid-id
+data: not-ok
diff --git a/dom/base/test/badMessageEvent2.eventsource^headers^ b/dom/base/test/badMessageEvent2.eventsource^headers^
new file mode 100644
index 0000000000..9bb8badcad
--- /dev/null
+++ b/dom/base/test/badMessageEvent2.eventsource^headers^
@@ -0,0 +1 @@
+Content-Type: text/event-stream
diff --git a/dom/base/test/browser.ini b/dom/base/test/browser.ini
new file mode 100644
index 0000000000..0386d433b5
--- /dev/null
+++ b/dom/base/test/browser.ini
@@ -0,0 +1,112 @@
+[DEFAULT]
+head = head.js
+support-files =
+ audio.ogg
+ dummy.html
+ empty.html
+ file_audioLoop.html
+ file_audioLoopInIframe.html
+ file_blocking_image.html
+ file_bug902350.html
+ file_bug902350_frame.html
+ file_bug1011748_redirect.sjs
+ file_bug1011748_OK.sjs
+ file_bug1303838.html
+ file_bug1303838_target.html
+ file_bug1303838_target_foo.html
+ file_bug1303838_target_bar.html
+ file_bug1303838_target_baz.html
+ file_bug1303838_target_ifoo.html
+ file_bug1303838_target_ibar.html
+ file_bug1303838_target_ibaz.html
+ file_bug1303838_with_iframe.html
+ file_messagemanager_unload.html
+ file_use_counter_bfcache.html
+ file_use_counter_bfcache_helper.html
+ file_use_counter_outer.html
+ file_use_counter_outer_display_none.html
+ file_use_counter_style.html
+ file_use_counter_svg_getElementById.svg
+ file_use_counter_svg_currentScale.svg
+ file_use_counter_svg_fill_pattern_definition.svg
+ file_use_counter_svg_fill_pattern.svg
+ file_use_counter_svg_fill_pattern_internal.svg
+ file_use_counter_svg_fill_pattern_data.svg
+ file_webaudio_startstop.html
+ !/image/test/mochitest/shaver.png
+
+
+[browser_blocking_image.js]
+[browser_bug902350.js]
+tags = mcb
+[browser_bug1011748.js]
+[browser_bug1058164.js]
+[browser_force_process_selector.js]
+skip-if =
+ verify
+ (os == 'win' && os_version == '10.0' && bits == 64 && asan)
+ (os == "linux" && bits == 64 && os_version == "18.04" && asan) # this only makes sense with e10s-multi , Bug 1651357
+[browser_messagemanager_loadprocessscript.js]
+[browser_aboutnewtab_process_selection.js]
+skip-if =
+ os == 'linux' && bits == 64 #Bug 1618098
+ os == 'mac' && fission # Bug 1618098
+[browser_messagemanager_targetframeloader.js]
+[browser_messagemanager_unload.js]
+skip-if = fission # Fails with Fission, and we're unlikely to spend time to fix it. (bug 1587490)
+[browser_pagehide_on_tab_close.js]
+skip-if = true # this tests non-e10s behavior.
+[browser_promiseDocumentFlushed.js]
+[browser_state_notifications.js]
+skip-if = true # Bug 1271028
+[browser_use_counters.js]
+skip-if = verify
+[browser_timeout_throttling_with_audio_playback.js]
+skip-if = (os == "win" && processor == "aarch64") # aarch64 due to bug 1536566
+[browser_bug1303838.js]
+skip-if =
+ os == "mac" && os_version == "10.15" && !debug # Bug 1703712
+[browser_bug1691214.js]
+skip-if =
+ os == 'win' # Bug 1692963
+ os == "mac" # Bug 1692963
+ os == 'linux' # Bug 1775696
+
+support-files =
+ file_bug1691214.html
+ file_bug1700871.html
+[browser_inputStream_structuredClone.js]
+[browser_multiple_popups.js]
+skip-if =
+ (os == 'win' && !debug)
+ (os == "mac" && !debug) # Bug 1505235, Bug 1661132 (osx)
+ socketprocess_networking
+support-files = browser_multiple_popups.html
+[browser_bug1554070.js]
+support-files =
+ file_bug1554070_1.html
+ file_bug1554070_2.html
+[browser_chromeutils_getalldomprocesses.js]
+[browser_chromeutils_isdomobject.js]
+[browser_outline_refocus.js]
+[browser_bug1703472.js]
+support-files =
+ file_bug1703472.html
+[browser_data_documents_aboutmemory.js]
+[browser_form_validity_popup_submit.js]
+[browser_refresh_content.js]
+support-files =
+ green.png
+ red.png
+ file_browser_refresh_content.html
+ file_browser_refresh_expired_resource.sjs
+ file_browser_refresh_non_cacheable.sjs
+ file_browser_refresh_image.sjs
+ file_browser_refresh_iframe.sjs
+[browser_page_load_event_telemetry.js]
+[browser_xml_toggle.js]
+[browser_user_input_handling_delay.js]
+[browser_user_input_handling_delay_bfcache.js]
+[browser_user_input_handling_delay_aboutblank.js]
+[browser_user_input_handling_delay_invisible_iframe.js]
+[browser_user_input_handling_delay_reload_ticks.js]
diff --git a/dom/base/test/browser_aboutnewtab_process_selection.js b/dom/base/test/browser_aboutnewtab_process_selection.js
new file mode 100644
index 0000000000..101f408483
--- /dev/null
+++ b/dom/base/test/browser_aboutnewtab_process_selection.js
@@ -0,0 +1,137 @@
+const TEST_URL = "http://www.example.com/browser/dom/base/test/dummy.html";
+const TEST_URL_2 = "http://example.org/browser/dom/base/test/dummy.html";
+const PRELOADED_STATE = "preloaded";
+
+var ppmm = Services.ppmm;
+
+add_task(async function () {
+ // We want to count processes in this test, so let's disable the pre-allocated process manager.
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.ipc.processPrelaunch.enabled", false],
+ ["dom.ipc.processCount", 10],
+ ["dom.ipc.processCount.webIsolated", 10],
+ ["dom.ipc.keepProcessesAlive.web", 10],
+ ],
+ });
+});
+
+add_task(async function () {
+ // This test is only relevant in e10s.
+ if (!gMultiProcessBrowser) {
+ return;
+ }
+
+ ppmm.releaseCachedProcesses();
+
+ // Wait for the preloaded browser to load.
+ await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
+
+ // Store the number of processes.
+ let expectedChildCount = ppmm.childCount;
+
+ // Open 3 tabs using the preloaded browser.
+ let tabs = [];
+ for (let i = 0; i < 3; i++) {
+ BrowserOpenTab();
+ tabs.unshift(gBrowser.selectedTab);
+ await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
+
+ // Check that the process count did not change.
+ is(
+ ppmm.childCount,
+ expectedChildCount,
+ "Preloaded browser should not create a new content process."
+ );
+ }
+
+ // Navigate to a content page from the parent side.
+ //
+ // We should create a new content process.
+ expectedChildCount += 1;
+ BrowserTestUtils.loadURIString(tabs[0].linkedBrowser, TEST_URL);
+ await BrowserTestUtils.browserLoaded(tabs[0].linkedBrowser, false, TEST_URL);
+ is(
+ ppmm.childCount,
+ expectedChildCount,
+ "Navigating away from the preloaded browser (parent side) should create a new content process."
+ );
+
+ // Navigate to the same content page from the child side.
+ //
+ // We should create a new content process.
+ expectedChildCount += 1;
+ await BrowserTestUtils.switchTab(gBrowser, tabs[1]);
+ await SpecialPowers.spawn(tabs[1].linkedBrowser, [TEST_URL], url => {
+ content.location.href = url;
+ });
+ await BrowserTestUtils.browserLoaded(tabs[1].linkedBrowser, false, TEST_URL);
+ is(
+ ppmm.childCount,
+ expectedChildCount,
+ "Navigating away from the preloaded browser (child side, same-origin) should create a new content process."
+ );
+
+ // Navigate to a new content page from the child side.
+ //
+ // We should create a new content process.
+ expectedChildCount += 1;
+ await BrowserTestUtils.switchTab(gBrowser, tabs[2]);
+ await ContentTask.spawn(tabs[2].linkedBrowser, TEST_URL_2, url => {
+ content.location.href = url;
+ });
+ await BrowserTestUtils.browserLoaded(
+ tabs[2].linkedBrowser,
+ false,
+ TEST_URL_2
+ );
+ is(
+ ppmm.childCount,
+ expectedChildCount,
+ "Navigating away from the preloaded browser (child side, cross-origin) should create a new content process."
+ );
+
+ for (let tab of tabs) {
+ BrowserTestUtils.removeTab(tab);
+ }
+
+ // Make sure the preload browser does not keep any of the new processes alive.
+ NewTabPagePreloading.removePreloadedBrowser(window);
+
+ // Since we kept alive all the processes, we can shut down the ones that do
+ // not host any tabs reliably.
+ ppmm.releaseCachedProcesses();
+});
+
+add_task(async function preloaded_state_attribute() {
+ // Wait for a preloaded browser to exist, use it, and then create another one
+ await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
+ let preloadedTabState =
+ gBrowser.preloadedBrowser.getAttribute("preloadedState");
+ is(
+ preloadedTabState,
+ PRELOADED_STATE,
+ "Sanity check that the first preloaded browser has the correct attribute"
+ );
+
+ BrowserOpenTab();
+ await BrowserTestUtils.maybeCreatePreloadedBrowser(gBrowser);
+
+ // Now check that the tabs have the correct browser attributes set
+ is(
+ gBrowser.selectedBrowser.hasAttribute("preloadedState"),
+ false,
+ "The opened tab consumed the preloaded browser and removed the attribute"
+ );
+
+ preloadedTabState = gBrowser.preloadedBrowser.getAttribute("preloadedState");
+ is(
+ preloadedTabState,
+ PRELOADED_STATE,
+ "The preloaded browser has the correct attribute"
+ );
+
+ // Remove tabs and preloaded browsers
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ NewTabPagePreloading.removePreloadedBrowser(window);
+});
diff --git a/dom/base/test/browser_blocking_image.js b/dom/base/test/browser_blocking_image.js
new file mode 100644
index 0000000000..5749937f07
--- /dev/null
+++ b/dom/base/test/browser_blocking_image.js
@@ -0,0 +1,183 @@
+const TEST_URI =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+ ) + "file_blocking_image.html";
+
+/**
+ * Loading an image from https:// should work.
+ */
+add_task(async function load_image_from_https_test() {
+ let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ gBrowser.selectedTab = tab;
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ function imgListener(img) {
+ return new Promise((resolve, reject) => {
+ img.addEventListener("load", () => resolve());
+ img.addEventListener("error", () => reject());
+ });
+ }
+
+ let img = content.document.createElement("img");
+ img.src = "https://example.com/tests/image/test/mochitest/shaver.png";
+ content.document.body.appendChild(img);
+
+ try {
+ await imgListener(img);
+ Assert.ok(true);
+ } catch (e) {
+ Assert.ok(false);
+ }
+ });
+
+ gBrowser.removeTab(tab);
+});
+
+/**
+ * Loading an image from http:// should be rejected.
+ */
+add_task(async function load_image_from_http_test() {
+ let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ gBrowser.selectedTab = tab;
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ function imgListener(img) {
+ return new Promise((resolve, reject) => {
+ img.addEventListener("load", () => reject());
+ img.addEventListener("error", () => resolve());
+ });
+ }
+
+ let img = content.document.createElement("img");
+ img.src = "http://example.com/tests/image/test/mochitest/shaver.png";
+ content.document.body.appendChild(img);
+
+ try {
+ await imgListener(img);
+ Assert.ok(true);
+ } catch (e) {
+ Assert.ok(false);
+ }
+ });
+
+ gBrowser.removeTab(tab);
+});
+
+/**
+ * Loading an image from http:// immediately after loading from https://
+ * The load from https:// should be replaced.
+ */
+add_task(async function load_https_and_http_test() {
+ let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ // Clear image cache, otherwise in non-e10s mode the image might be cached by
+ // previous test, and make the image from https is loaded immediately.
+ let imgTools = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools);
+ let imageCache = imgTools.getImgCacheForDocument(window.document);
+ imageCache.clearCache(false); // false=content
+
+ gBrowser.selectedTab = tab;
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ function imgListener(img) {
+ return new Promise((resolve, reject) => {
+ img.addEventListener("load", () => reject());
+ img.addEventListener("error", () => resolve());
+ });
+ }
+
+ let img = content.document.createElement("img");
+ img.src = "https://example.com/tests/image/test/mochitest/shaver.png";
+ img.src = "http://example.com/tests/image/test/mochitest/shaver.png";
+
+ content.document.body.appendChild(img);
+
+ try {
+ await imgListener(img);
+ Assert.ok(true);
+ } catch (e) {
+ Assert.ok(false);
+ }
+ });
+
+ gBrowser.removeTab(tab);
+});
+
+/**
+ * Loading an image from https.
+ * Then after we have size information of the image, we immediately change the
+ * location to a http:// site (hence should be blocked by CSP).
+ */
+add_task(async function block_pending_request_test() {
+ let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ gBrowser.selectedTab = tab;
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ let wrapper = {
+ _resolve: null,
+ _sizeAvail: false,
+
+ sizeAvailable(request) {
+ // In non-e10s mode the image may have already been cached, so sometimes
+ // sizeAvailable() is called earlier then waitUntilSizeAvailable().
+ if (this._resolve) {
+ this._resolve();
+ } else {
+ this._sizeAvail = true;
+ }
+ },
+
+ waitUntilSizeAvailable() {
+ return new Promise(resolve => {
+ this._resolve = resolve;
+ if (this._sizeAvail) {
+ resolve();
+ }
+ });
+ },
+
+ QueryInterface(aIID) {
+ if (aIID.equals(Ci.imgIScriptedNotificationObserver)) {
+ return this;
+ }
+ throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
+ },
+ };
+
+ let observer = Cc["@mozilla.org/image/tools;1"]
+ .getService(Ci.imgITools)
+ .createScriptedObserver(wrapper);
+
+ let img = content.document.createElement("img");
+ img.src = "https://example.com/tests/image/test/mochitest/shaver.png";
+
+ let req = img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
+ img.addObserver(observer);
+
+ content.document.body.appendChild(img);
+
+ info("Wait until Size Available");
+ await wrapper.waitUntilSizeAvailable();
+ info("Size Available now!");
+ img.removeObserver(observer);
+
+ // Now we change to load from http:// site, which will be blocked.
+ img.src = "http://example.com/tests/image/test/mochitest/shaver.png";
+
+ Assert.equal(
+ img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST),
+ req,
+ "CURRENT_REQUEST shouldn't be replaced."
+ );
+ });
+
+ gBrowser.removeTab(tab);
+});
diff --git a/dom/base/test/browser_bug1011748.js b/dom/base/test/browser_bug1011748.js
new file mode 100644
index 0000000000..566e1347e9
--- /dev/null
+++ b/dom/base/test/browser_bug1011748.js
@@ -0,0 +1,31 @@
+const gHttpTestRoot = "http://example.com/browser/dom/base/test/";
+
+add_task(async function () {
+ var statusTexts = [];
+ var xhr = new XMLHttpRequest();
+ var observer = {
+ observe(aSubject, aTopic, aData) {
+ try {
+ var channel = aSubject.QueryInterface(Ci.nsIHttpChannel);
+ channel.getResponseHeader("Location");
+ } catch (e) {
+ return;
+ }
+ statusTexts.push(xhr.statusText);
+ },
+ };
+
+ Services.obs.addObserver(observer, "http-on-examine-response");
+ await new Promise(resolve => {
+ xhr.addEventListener("load", function () {
+ statusTexts.push(this.statusText);
+ is(statusTexts[0], "", "Empty statusText value for HTTP 302");
+ is(statusTexts[1], "OK", "OK statusText value for the redirect.");
+ resolve();
+ });
+ xhr.open("GET", gHttpTestRoot + "file_bug1011748_redirect.sjs", true);
+ xhr.send();
+ });
+
+ Services.obs.removeObserver(observer, "http-on-examine-response");
+});
diff --git a/dom/base/test/browser_bug1058164.js b/dom/base/test/browser_bug1058164.js
new file mode 100644
index 0000000000..0bb1098ef2
--- /dev/null
+++ b/dom/base/test/browser_bug1058164.js
@@ -0,0 +1,238 @@
+/* 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/. */
+
+"use strict";
+
+SpecialPowers.pushPrefEnv({
+ set: [["security.allow_eval_with_system_principal", true]],
+});
+
+const PAGE =
+ "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
+
+let gListenerId = 0;
+
+/**
+ * Adds a content event listener on the given browser element. NOTE: this test
+ * is checking the behavior of pageshow and pagehide as seen by frame scripts,
+ * so it is specifically implemented using the message message manager.
+ * Similar to BrowserTestUtils.waitForContentEvent, but the listener will fire
+ * until it is removed. A callable object is returned that, when called, removes
+ * the event listener. Note that this function works even if the browser's
+ * frameloader is swapped.
+ *
+ * @param {xul:browser} browser
+ * The browser element to listen for events in.
+ * @param {string} eventName
+ * Name of the event to listen to.
+ * @param {function} listener
+ * Function to call in parent process when event fires.
+ * Not passed any arguments.
+ * @param {function} checkFn [optional]
+ * Called with the Event object as argument, should return true if the
+ * event is the expected one, or false if it should be ignored and
+ * listening should continue. If not specified, the first event with
+ * the specified name resolves the returned promise. This is called
+ * within the content process and can have no closure environment.
+ *
+ * @returns function
+ * If called, the return value will remove the event listener.
+ */
+function addContentEventListenerWithMessageManager(
+ browser,
+ eventName,
+ listener,
+ checkFn
+) {
+ let id = gListenerId++;
+ let checkFnSource = checkFn
+ ? encodeURIComponent(escape(checkFn.toSource()))
+ : "";
+
+ // To correctly handle frameloader swaps, we load a frame script
+ // into all tabs but ignore messages from the ones not related to
+ // |browser|.
+
+ /* eslint-disable no-eval */
+ function frameScript(innerId, innerEventName, innerCheckFnSource) {
+ let innerCheckFn;
+ if (innerCheckFnSource) {
+ innerCheckFn = eval(`(() => (${unescape(innerCheckFnSource)}))()`);
+ }
+
+ function innerListener(event) {
+ if (innerCheckFn && !innerCheckFn(event)) {
+ return;
+ }
+ sendAsyncMessage("ContentEventListener:Run", innerId);
+ }
+ function removeListener(msg) {
+ if (msg.data == innerId) {
+ removeMessageListener("ContentEventListener:Remove", removeListener);
+ removeEventListener(innerEventName, innerListener);
+ }
+ }
+ addMessageListener("ContentEventListener:Remove", removeListener);
+ addEventListener(innerEventName, innerListener);
+ }
+ /* eslint-enable no-eval */
+
+ let frameScriptSource = `data:,(${frameScript.toString()})(${id}, "${eventName}",
+ "${checkFnSource}")`;
+
+ let mm = Services.mm;
+
+ function runListener(msg) {
+ if (msg.data == id && msg.target == browser) {
+ listener();
+ }
+ }
+ mm.addMessageListener("ContentEventListener:Run", runListener);
+
+ let needCleanup = true;
+
+ let unregisterFunction = function () {
+ if (!needCleanup) {
+ return;
+ }
+ needCleanup = false;
+ mm.removeMessageListener("ContentEventListener:Run", runListener);
+ mm.broadcastAsyncMessage("ContentEventListener:Remove", id);
+ mm.removeDelayedFrameScript(frameScriptSource);
+ };
+
+ function cleanupObserver(subject, topic, data) {
+ if (subject == browser.messageManager) {
+ unregisterFunction();
+ }
+ }
+
+ mm.loadFrameScript(frameScriptSource, true);
+
+ return unregisterFunction;
+}
+
+/**
+ * Returns a Promise that resolves when it sees a pageshow and
+ * pagehide events in a particular order, where each event must
+ * have the persisted property set to true. Will cause a test
+ * failure to be logged if it sees an event out of order.
+ *
+ * @param browser (<xul:browser>)
+ * The browser to expect the events from.
+ * @param expectedOrder (array)
+ * An array of strings describing what order the pageshow
+ * and pagehide events should be in.
+ * Example:
+ * ["pageshow", "pagehide", "pagehide", "pageshow"]
+ * @returns Promise
+ */
+function prepareForVisibilityEvents(browser, expectedOrder) {
+ return new Promise(resolve => {
+ let order = [];
+
+ let rmvHide, rmvShow;
+
+ let checkSatisfied = () => {
+ if (order.length < expectedOrder.length) {
+ // We're still waiting...
+ return;
+ } else {
+ rmvHide();
+ rmvShow();
+
+ for (let i = 0; i < expectedOrder.length; ++i) {
+ is(order[i], expectedOrder[i], "Got expected event");
+ }
+ resolve();
+ }
+ };
+
+ let eventListener = type => {
+ order.push(type);
+ checkSatisfied();
+ };
+
+ let checkFn = e => e.persisted;
+
+ rmvHide = addContentEventListenerWithMessageManager(
+ browser,
+ "pagehide",
+ () => eventListener("pagehide"),
+ checkFn
+ );
+ rmvShow = addContentEventListenerWithMessageManager(
+ browser,
+ "pageshow",
+ () => eventListener("pageshow"),
+ checkFn
+ );
+ });
+}
+
+/**
+ * Tests that frame scripts get pageshow / pagehide events when
+ * swapping browser frameloaders (which occurs when moving a tab
+ * into a different window).
+ */
+add_task(async function test_swap_frameloader_pagevisibility_events() {
+ // Disable window occlusion. Bug 1733955
+ if (navigator.platform.indexOf("Win") == 0) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["widget.windows.window_occlusion_tracking.enabled", false]],
+ });
+ }
+
+ // Load a new tab that we'll tear out...
+ let tab = BrowserTestUtils.addTab(gBrowser, PAGE);
+ gBrowser.selectedTab = tab;
+ let firstBrowser = tab.linkedBrowser;
+ await BrowserTestUtils.browserLoaded(firstBrowser);
+
+ // Swap the browser out to a new window
+ let newWindow = gBrowser.replaceTabWithWindow(tab);
+
+ // We have to wait for the window to load so we can get the selected browser
+ // to listen to.
+ await BrowserTestUtils.waitForEvent(newWindow, "DOMContentLoaded");
+ let newWindowBrowser = newWindow.gBrowser.selectedBrowser;
+
+ // Wait for the expected pagehide and pageshow events on the initial browser
+ await prepareForVisibilityEvents(newWindowBrowser, ["pagehide", "pageshow"]);
+
+ // Now let's send the browser back to the original window
+
+ // First, create a new, empty browser tab to replace the window with
+ let newTab = BrowserTestUtils.addTab(gBrowser);
+ gBrowser.selectedTab = newTab;
+ let emptyBrowser = newTab.linkedBrowser;
+
+ // Wait for that initial doc to be visible because if its pageshow hasn't
+ // happened we don't confuse it with the other expected events.
+ await ContentTask.spawn(emptyBrowser, null, async () => {
+ if (content.document.visibilityState === "hidden") {
+ info("waiting for hidden emptyBrowser to be visible");
+ await ContentTaskUtils.waitForEvent(
+ content.document,
+ "visibilitychange",
+ {}
+ );
+ }
+ });
+
+ info("emptyBrowser is shown now.");
+
+ // The empty tab we just added show now fire a pagehide as its replaced,
+ // and a pageshow once the swap is finished.
+ let emptyBrowserPromise = prepareForVisibilityEvents(emptyBrowser, [
+ "pagehide",
+ "pageshow",
+ ]);
+
+ gBrowser.swapBrowsersAndCloseOther(newTab, newWindow.gBrowser.selectedTab);
+
+ await emptyBrowserPromise;
+
+ gBrowser.removeTab(gBrowser.selectedTab);
+});
diff --git a/dom/base/test/browser_bug1303838.js b/dom/base/test/browser_bug1303838.js
new file mode 100644
index 0000000000..a4d5ee3b26
--- /dev/null
+++ b/dom/base/test/browser_bug1303838.js
@@ -0,0 +1,368 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Test for bug 1303838.
+ * Load a tab with some links, emulate link clicks and check if the
+ * browser would switch to the existing target tab opened by previous
+ * link click if loadDivertedInBackground is set to true.
+ */
+
+"use strict";
+
+const BASE_URL = "http://mochi.test:8888/browser/dom/base/test/";
+
+add_task(async function () {
+ // On Linux, in our test automation, the mouse cursor floats over
+ // the first tab, which causes it to be warmed up when tab warming
+ // is enabled. The TabSwitchDone event doesn't fire until the warmed
+ // tab is evicted, which is after a few seconds. That means that
+ // this test ends up taking longer than we'd like, since its waiting
+ // for the TabSwitchDone event between tab switches.
+ //
+ // So now we make sure that warmed tabs are evicted very shortly
+ // after warming to avoid the test running too long.
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.tabs.remote.warmup.unloadDelayMs", 50]],
+ });
+ await testLinkClick(false, false);
+ await testLinkClick(false, true);
+ await testLinkClick(true, false);
+ await testLinkClick(true, true);
+});
+
+async function waitForTestReady(loadDivertedInBackground, tab) {
+ if (!loadDivertedInBackground) {
+ await BrowserTestUtils.switchTab(gBrowser, tab);
+ } else {
+ await new Promise(resolve => setTimeout(resolve, 0));
+ }
+}
+
+async function testLinkClick(withFrame, loadDivertedInBackground) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.tabs.loadDivertedInBackground", loadDivertedInBackground]],
+ });
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ BASE_URL +
+ (withFrame ? "file_bug1303838_with_iframe.html" : "file_bug1303838.html")
+ );
+ is(gBrowser.tabs.length, 2, "check tabs.length");
+ is(gBrowser.selectedTab, tab, "check selectedTab");
+
+ info(
+ "Test normal links with loadDivertedInBackground=" +
+ loadDivertedInBackground +
+ ", withFrame=" +
+ withFrame
+ );
+
+ let testTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+ await clickLink(withFrame, "#link-1", tab.linkedBrowser);
+ let testTab = await testTabPromise;
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#link-2",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#link-3",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#link-4",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ // Location APIs shouldn't steal focus.
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#link-5",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ /* awaitTabSwitch = */ false
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(gBrowser.selectedTab, tab, "check selectedTab");
+
+ await waitForTestReady(/* diverted = */ true, tab);
+ await clickLink(
+ withFrame,
+ "#link-6",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ /* awaitTabSwitch = */ false
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(gBrowser.selectedTab, tab, "check selectedTab");
+
+ await waitForTestReady(/* diverted = */ true, tab);
+ let loaded = BrowserTestUtils.browserLoaded(
+ testTab.linkedBrowser,
+ true,
+ "data:text/html;charset=utf-8,testFrame"
+ );
+ await clickLink(
+ withFrame,
+ "#link-7",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground,
+ false
+ );
+ await loaded;
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ info(
+ "Test anchor links with loadDivertedInBackground=" +
+ loadDivertedInBackground +
+ ", withFrame=" +
+ withFrame
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#anchor-link-1",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#anchor-link-2",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#anchor-link-3",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ info(
+ "Test iframe links with loadDivertedInBackground=" +
+ loadDivertedInBackground +
+ ", withFrame=" +
+ withFrame
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#frame-link-1",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground,
+ true
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#frame-link-2",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground,
+ true
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ await waitForTestReady(loadDivertedInBackground, tab);
+ await clickLink(
+ withFrame,
+ "#frame-link-3",
+ tab.linkedBrowser,
+ testTab.linkedBrowser,
+ !loadDivertedInBackground,
+ true
+ );
+ is(gBrowser.tabs.length, 3, "check tabs.length");
+ is(
+ gBrowser.selectedTab,
+ loadDivertedInBackground ? tab : testTab,
+ "check selectedTab"
+ );
+
+ BrowserTestUtils.removeTab(testTab);
+ BrowserTestUtils.removeTab(tab);
+}
+
+function clickLink(
+ isFrame,
+ linkId,
+ browser,
+ testBrowser,
+ awaitTabSwitch = false,
+ targetsFrame = false,
+ locationChangeNum = 1
+) {
+ let promises = [];
+ if (awaitTabSwitch) {
+ promises.push(waitForTabSwitch(gBrowser));
+ }
+ if (testBrowser) {
+ promises.push(
+ waitForLocationChange(targetsFrame, testBrowser, locationChangeNum)
+ );
+ }
+
+ info("BC children: " + browser.browsingContext.children.length);
+ promises.push(
+ BrowserTestUtils.synthesizeMouseAtCenter(
+ linkId,
+ {},
+ isFrame ? browser.browsingContext.children[0] : browser
+ )
+ );
+ return Promise.all(promises);
+}
+
+function waitForTabSwitch(tabbrowser) {
+ info("Waiting for TabSwitch");
+ return new Promise(resolve => {
+ tabbrowser.addEventListener("TabSwitchDone", function onSwitch() {
+ info("TabSwitch done");
+ tabbrowser.removeEventListener("TabSwitchDone", onSwitch);
+ resolve(tabbrowser.selectedTab);
+ });
+ });
+}
+
+let locationChangeListener;
+function waitForLocationChange(isFrame, browser, locationChangeNum) {
+ if (isFrame) {
+ return waitForFrameLocationChange(browser, locationChangeNum);
+ }
+
+ info("Waiting for " + locationChangeNum + " LocationChange");
+ return new Promise(resolve => {
+ let seen = 0;
+ locationChangeListener = {
+ onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
+ info("LocationChange: " + aLocation.spec);
+ if (++seen == locationChangeNum) {
+ browser.removeProgressListener(this);
+ resolve();
+ }
+ },
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIWebProgressListener",
+ "nsISupportsWeakReference",
+ ]),
+ };
+ browser.addProgressListener(locationChangeListener);
+ });
+}
+
+function waitForFrameLocationChange(browser, locationChangeNum) {
+ info("Waiting for " + locationChangeNum + " LocationChange in subframe");
+ return SpecialPowers.spawn(browser, [locationChangeNum], async changeNum => {
+ let seen = 0;
+ let webprogress = content.docShell.QueryInterface(Ci.nsIWebProgress);
+ await new Promise(resolve => {
+ locationChangeListener = {
+ onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
+ info("LocationChange: " + aLocation.spec);
+ if (++seen == changeNum) {
+ resolve();
+ }
+ },
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIWebProgressListener",
+ "nsISupportsWeakReference",
+ ]),
+ };
+ webprogress.addProgressListener(
+ locationChangeListener,
+ Ci.nsIWebProgress.NOTIFY_LOCATION
+ );
+ });
+ webprogress.removeProgressListener(locationChangeListener);
+ });
+}
diff --git a/dom/base/test/browser_bug1554070.js b/dom/base/test/browser_bug1554070.js
new file mode 100644
index 0000000000..a5efc17e19
--- /dev/null
+++ b/dom/base/test/browser_bug1554070.js
@@ -0,0 +1,49 @@
+"use strict";
+
+const HTTPS_TEST_ROOT = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+
+const URL0 = HTTPS_TEST_ROOT + "file_bug1554070_1.html";
+const URL1 = HTTPS_TEST_ROOT + "file_bug1554070_2.html";
+const URL2 = "https://example.org/";
+
+add_task(async function () {
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ waitForLoad: true,
+ });
+
+ let browser = tab.linkedBrowser;
+
+ function click() {
+ return SpecialPowers.spawn(browser, [], () => {
+ let anchor = content.document.querySelector("a");
+ anchor.click();
+ });
+ }
+
+ // Load file_bug1554070_1.html.
+ BrowserTestUtils.loadURIString(browser, URL0);
+ await BrowserTestUtils.browserLoaded(browser, false, URL0);
+ is(gBrowser.currentURI.spec, URL0, "loaded file_bug1554070_1.html");
+
+ // Click the link in file_bug1554070_1.html. It should open
+ // file_bug1554070_2.html in the current tab.
+ await click();
+ await BrowserTestUtils.browserLoaded(browser, false, URL1);
+ is(gBrowser.currentURI.spec, URL1, "loaded file_bug1554070_2.html");
+
+ // Click the link in file_bug1554070_2.html. It should open example.org in
+ // a new tab.
+ await Promise.all([
+ click(),
+ BrowserTestUtils.waitForNewTab(gBrowser, URL2, true),
+ ]);
+ is(gBrowser.tabs.length, 3, "got new tab");
+ is(gBrowser.currentURI.spec, URL2, "loaded example.org");
+
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/dom/base/test/browser_bug1691214.js b/dom/base/test/browser_bug1691214.js
new file mode 100644
index 0000000000..5f40df2ea3
--- /dev/null
+++ b/dom/base/test/browser_bug1691214.js
@@ -0,0 +1,122 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const BASE_URL = "http://mochi.test:8888/browser/dom/base/test/";
+
+add_task(async function bug1691214() {
+ await BrowserTestUtils.withNewTab(
+ BASE_URL + "file_bug1691214.html",
+ async function (browser) {
+ let win = await newFocusedWindow(function () {
+ return BrowserTestUtils.synthesizeMouseAtCenter("#link-1", {}, browser);
+ });
+ is(Services.focus.focusedWindow, win, "New window should be focused");
+
+ info("re-focusing the original window");
+
+ {
+ let focusBack = BrowserTestUtils.waitForEvent(window, "focus", true);
+ window.focus();
+ await focusBack;
+ is(Services.focus.focusedWindow, window, "should focus back");
+ }
+
+ info("Clicking on the second link.");
+
+ {
+ let focus = BrowserTestUtils.waitForEvent(win, "focus", true);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#link-2", {}, browser);
+ info("Waiting for re-focus of the opened window.");
+ await focus;
+ }
+
+ is(
+ Services.focus.focusedWindow,
+ win,
+ "Existing window should've been targeted and focused"
+ );
+
+ win.close();
+ }
+ );
+});
+
+// The tab has a form infinitely submitting to an iframe, and that shouldn't
+// switch focus back. For that, we open a window from the tab, make sure it's
+// focused, and then wait for three submissions (but since we need to listen to
+// trusted events from chrome code, we use the iframe load event instead).
+add_task(async function bug1700871() {
+ await BrowserTestUtils.withNewTab(
+ BASE_URL + "file_bug1700871.html",
+ async function (browser) {
+ let win = await newFocusedWindow(function () {
+ return BrowserTestUtils.synthesizeMouseAtCenter("#link-1", {}, browser);
+ });
+
+ is(Services.focus.focusedWindow, win, "New window should be focused");
+
+ info("waiting for three submit events and ensuring focus hasn't moved");
+
+ await SpecialPowers.spawn(browser, [], function () {
+ let pending = 3;
+ return new Promise(resolve => {
+ content.document
+ .querySelector("iframe")
+ .addEventListener("load", function (e) {
+ info("Got load on the frame: " + pending);
+ if (!--pending) {
+ resolve();
+ }
+ });
+ });
+ });
+
+ is(Services.focus.focusedWindow, win, "Focus shouldn't have moved");
+ win.close();
+ }
+ );
+});
+
+add_task(async function bug1793829() {
+ await BrowserTestUtils.withNewTab(
+ BASE_URL + "file_bug1691214.html",
+ async function (browser) {
+ let win = await newFocusedWindow(function () {
+ return BrowserTestUtils.synthesizeMouseAtCenter("#link-1", {}, browser);
+ });
+ is(Services.focus.focusedWindow, win, "New window should be focused");
+
+ info("re-focusing the original window");
+
+ {
+ let focusBack = BrowserTestUtils.waitForEvent(window, "focus", true);
+ window.focus();
+ await focusBack;
+ is(Services.focus.focusedWindow, window, "should focus back");
+ }
+
+ info("Trying to steal focus.");
+
+ await SpecialPowers.spawn(browser, [], function () {
+ content.document.clearUserGestureActivation();
+ content.document.getElementById("link-2").click();
+ });
+
+ // We need to test that nothing happened, which is hard without an
+ // arbitrary timeout.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(c => setTimeout(c, 2000));
+
+ is(
+ Services.focus.focusedWindow,
+ window,
+ "Shouldn't steal focus without user gesture"
+ );
+
+ win.close();
+ }
+ );
+});
diff --git a/dom/base/test/browser_bug1703472.js b/dom/base/test/browser_bug1703472.js
new file mode 100644
index 0000000000..ba4d10a63f
--- /dev/null
+++ b/dom/base/test/browser_bug1703472.js
@@ -0,0 +1,68 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const BASE_URL = "http://mochi.test:8888/browser/dom/base/test/";
+
+add_task(async function bug1703472() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.block_multiple_popups", true],
+ ["dom.disable_open_during_load", true],
+ ],
+ });
+
+ await BrowserTestUtils.withNewTab(
+ BASE_URL + "file_bug1703472.html",
+ async function (browser) {
+ info("Opening popup");
+ let win = await newFocusedWindow(function () {
+ return BrowserTestUtils.synthesizeMouseAtCenter(
+ "#openWindow",
+ {},
+ browser
+ );
+ });
+
+ info("re-focusing the original window");
+ {
+ let focusBack = BrowserTestUtils.waitForEvent(window, "focus", true);
+ window.focus();
+ await focusBack;
+ is(Services.focus.focusedWindow, window, "should focus back");
+ }
+
+ // The click to do window.open() should've consumed the user interaction,
+ // and an artificial .click() shouldn't count as a user interaction, so the
+ // page shouldn't be allowed to focus it again without user interaction.
+ info("Trying to steal focus without interaction");
+ await SpecialPowers.spawn(browser, [], function () {
+ content.document.querySelector("#focusWindow").click();
+ });
+
+ // We need to wait for something _not_ happening, so we need to use an arbitrary setTimeout.
+ await new Promise(resolve => {
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(resolve, 500);
+ });
+
+ is(Services.focus.focusedWindow, window, "should still be focused");
+
+ info("Trying to move focus with user interaction");
+ {
+ let focus = BrowserTestUtils.waitForEvent(win, "focus", true);
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#focusWindow",
+ {},
+ browser
+ );
+ await focus;
+ is(Services.focus.focusedWindow, win, "should focus back");
+ }
+
+ win.close();
+ }
+ );
+});
diff --git a/dom/base/test/browser_bug902350.js b/dom/base/test/browser_bug902350.js
new file mode 100644
index 0000000000..18b17c5953
--- /dev/null
+++ b/dom/base/test/browser_bug902350.js
@@ -0,0 +1,56 @@
+/*
+ * Mixed Content Block frame navigates for target="_top" - Test for Bug 902350
+ */
+
+add_task(async function mixed_content_block_for_target_top_test() {
+ const PREF_ACTIVE = "security.mixed_content.block_active_content";
+ const httpsTestRoot = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+ );
+
+ await SpecialPowers.pushPrefEnv({ set: [[PREF_ACTIVE, true]] });
+
+ let newTab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ waitForLoad: true,
+ });
+ let testBrowser = newTab.linkedBrowser;
+
+ var url = httpsTestRoot + "file_bug902350.html";
+ var frameUrl = httpsTestRoot + "file_bug902350_frame.html";
+ let loadPromise = BrowserTestUtils.browserLoaded(testBrowser, false, url);
+ let frameLoadPromise = BrowserTestUtils.browserLoaded(
+ testBrowser,
+ true,
+ frameUrl
+ );
+ BrowserTestUtils.loadURIString(testBrowser, url);
+ await loadPromise;
+ await frameLoadPromise;
+
+ // Find the iframe and click the link in it.
+ let insecureUrl = "http://example.com/";
+ let insecureLoadPromise = BrowserTestUtils.browserLoaded(
+ testBrowser,
+ false,
+ insecureUrl
+ );
+ SpecialPowers.spawn(testBrowser, [], function () {
+ var frame = content.document.getElementById("testing_frame");
+ var topTarget = frame.contentWindow.document.getElementById("topTarget");
+ topTarget.click();
+ });
+
+ // Navigating to insecure domain through target='_top' should succeed.
+ await insecureLoadPromise;
+
+ // The link click should not invoke the Mixed Content Blocker.
+ let { gIdentityHandler } = testBrowser.ownerGlobal;
+ ok(
+ !gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
+ "Mixed Content Doorhanger did not appear when trying to navigate top"
+ );
+
+ BrowserTestUtils.removeTab(newTab);
+});
diff --git a/dom/base/test/browser_chromeutils_getalldomprocesses.js b/dom/base/test/browser_chromeutils_getalldomprocesses.js
new file mode 100644
index 0000000000..aef5bcf12b
--- /dev/null
+++ b/dom/base/test/browser_chromeutils_getalldomprocesses.js
@@ -0,0 +1,62 @@
+add_task(async function testParentProcess() {
+ const [parentProcess] = ChromeUtils.getAllDOMProcesses();
+ // browser.xhtml is in the parent process, so its domProcess is the parent process one
+ is(
+ parentProcess,
+ window.browsingContext.currentWindowGlobal.domProcess,
+ "The first element is the parent process"
+ );
+ is(
+ parentProcess.osPid,
+ Services.appinfo.processID,
+ "We got the right OS Pid"
+ );
+ is(parentProcess.childID, 0, "Parent process has childID set to 0");
+});
+
+add_task(async function testContentProcesses() {
+ info("Open a tab in a content process");
+ BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, "about:blank");
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+ info("Sanity checks against all returned elements of getAllDOMProcesses");
+ const processes = ChromeUtils.getAllDOMProcesses();
+ const allPids = [],
+ allChildIDs = [];
+ for (const process of processes) {
+ ok(
+ process instanceof Ci.nsIDOMProcessParent,
+ `Each element of the array is a nsIDOMProcessParent (${process})`
+ );
+ ok(process.osPid > 0, `OS Pid looks correct ${process.osPid}`);
+ if (process == processes[0]) {
+ is(
+ process.childID,
+ 0,
+ `Child ID is 0 for the parent process, which is the first element of the returned array`
+ );
+ is(
+ process.remoteType,
+ null,
+ "The main process's remote type should be NOT_REMOTE"
+ );
+ } else {
+ ok(process.childID > 0, `Child ID looks also correct ${process.childID}`);
+ ok(process.remoteType, "Should have a remote type");
+ }
+
+ ok(
+ !allPids.includes(process.osPid),
+ "We only get one nsIDOMProcessParent per OS process == each osPid is different"
+ );
+ allPids.push(process.osPid);
+ ok(!allChildIDs.includes(process.childID), "Each childID is different");
+ allChildIDs.push(process.childID);
+ }
+
+ info("Search for the nsIDOMProcessParent for the opened tab");
+ const { currentWindowGlobal } = gBrowser.selectedBrowser.browsingContext;
+ const tabProcess = currentWindowGlobal.domProcess;
+ ok(processes.includes(tabProcess), "Found the tab process in the list");
+ is(tabProcess.osPid, currentWindowGlobal.osPid, "We got the right OS Pid");
+});
diff --git a/dom/base/test/browser_chromeutils_isdomobject.js b/dom/base/test/browser_chromeutils_isdomobject.js
new file mode 100644
index 0000000000..14a5d69898
--- /dev/null
+++ b/dom/base/test/browser_chromeutils_isdomobject.js
@@ -0,0 +1,115 @@
+"use strict";
+
+add_task(async function invalidArgument() {
+ const args = [undefined, null, 42, "foo"];
+
+ for (const argument of args) {
+ let hadException = false;
+ try {
+ ChromeUtils.isDOMObject(argument);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+ }
+});
+
+add_task(async function NoUnwrap() {
+ const args = [
+ window.document,
+ window.document.childNodes,
+ new DocumentFragment(),
+ new Response(),
+ new URL("https://example.com"),
+ ];
+
+ for (const argument of args) {
+ ok(
+ ChromeUtils.isDOMObject(argument, false),
+ `${ChromeUtils.getClassName(
+ argument
+ )} to be a DOM object with unwrap=false`
+ );
+ }
+
+ ok(
+ !ChromeUtils.isDOMObject(window, false),
+ `${ChromeUtils.getClassName(
+ window
+ )} not to be a DOM object with unwrap=false`
+ );
+});
+
+add_task(async function DOMObjects() {
+ const args = [
+ window,
+ window.document,
+ window.document.childNodes,
+ new DocumentFragment(),
+ new Response(),
+ new URL("https://example.com"),
+ ];
+
+ for (const argument of args) {
+ ok(
+ ChromeUtils.isDOMObject(argument),
+ `${ChromeUtils.getClassName(argument)} to be a DOM object`
+ );
+ }
+});
+
+add_task(async function nonDOMObjects() {
+ const args = [new Object(), {}, []];
+
+ for (const argument of args) {
+ ok(
+ !ChromeUtils.isDOMObject(argument),
+ `${ChromeUtils.getClassName(argument)} not to be a DOM object`
+ );
+ }
+});
+
+add_task(async function DOMObjects_contentProcess() {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: `data:text/html,<div>`,
+ },
+ async function (browser) {
+ await SpecialPowers.spawn(browser, [], async () => {
+ const args = [
+ content,
+ content.document,
+ content.document.querySelector("div"),
+ content.document.childNodes,
+ new content.DocumentFragment(),
+ new content.URL("https://example.com"),
+ ];
+
+ for (const argument of args) {
+ ok(
+ ChromeUtils.isDOMObject(argument),
+ `${ChromeUtils.getClassName(
+ argument
+ )} in content to be a DOM object`
+ );
+ }
+
+ ok(
+ !ChromeUtils.isDOMObject({}),
+ `${ChromeUtils.getClassName({})} in content not to be a DOM object`
+ );
+
+ // unwrap=false
+ for (const argument of args) {
+ ok(
+ !ChromeUtils.isDOMObject(argument, false),
+ `${ChromeUtils.getClassName(
+ argument
+ )} in content not to be a DOM object with unwrap=false`
+ );
+ }
+ });
+ }
+ );
+});
diff --git a/dom/base/test/browser_data_documents_aboutmemory.js b/dom/base/test/browser_data_documents_aboutmemory.js
new file mode 100644
index 0000000000..5c534a83b6
--- /dev/null
+++ b/dom/base/test/browser_data_documents_aboutmemory.js
@@ -0,0 +1,20 @@
+add_task(async function () {
+ const doc = new DOMParser().parseFromString("<p>dadada</p>", "text/html");
+
+ let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].getService(
+ Ci.nsIMemoryReporterManager
+ );
+
+ let amount = 0;
+ const handleReport = (aProcess, aPath, aKind, aUnits, aAmount) => {
+ const regex = new RegExp(".*/window-objects/.*/data-documents/.*");
+ if (regex.test(aPath)) {
+ amount += aAmount;
+ }
+ };
+
+ await new Promise(r =>
+ mgr.getReports(handleReport, null, r, null, /* anonymized = */ false)
+ );
+ ok(amount > 0, "Got data documents amount");
+});
diff --git a/dom/base/test/browser_force_process_selector.js b/dom/base/test/browser_force_process_selector.js
new file mode 100644
index 0000000000..15157b240d
--- /dev/null
+++ b/dom/base/test/browser_force_process_selector.js
@@ -0,0 +1,38 @@
+"use strict";
+
+const CONTENT_CREATED = "ipc:content-created";
+
+// Make sure that BTU.withNewTab({ ..., forceNewProcess: true }) loads
+// new tabs in their own process.
+async function spawnNewAndTest(recur, pids) {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank", forceNewProcess: true },
+ async function (browser) {
+ // Make sure our new browser is in its own process.
+ let newPid = browser.frameLoader.remoteTab.osPid;
+ ok(!pids.has(newPid), "new tab is in its own process: " + recur);
+ pids.add(newPid);
+
+ if (recur) {
+ await spawnNewAndTest(recur - 1, pids);
+ } else {
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:blank" },
+ function (lastBrowser) {
+ let lastPid = lastBrowser.frameLoader.remoteTab.osPid;
+ ok(pids.has(lastPid), "final tab cannot be in its own process");
+ }
+ );
+ }
+ }
+ );
+}
+
+add_task(async function test() {
+ let curPid = gBrowser.selectedBrowser.frameLoader.remoteTab.osPid;
+ let maxCount = Services.prefs.getIntPref("dom.ipc.processCount");
+
+ // Use at least one more tab than max processes or at least 5 to make this
+ // test interesting.
+ await spawnNewAndTest(Math.max(maxCount + 1, 5), new Set([curPid]));
+});
diff --git a/dom/base/test/browser_form_validity_popup_submit.js b/dom/base/test/browser_form_validity_popup_submit.js
new file mode 100644
index 0000000000..2cefbf9d98
--- /dev/null
+++ b/dom/base/test/browser_form_validity_popup_submit.js
@@ -0,0 +1,55 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+async function promiseValidityPopupShown() {
+ await BrowserTestUtils.waitForEvent(
+ window,
+ "popupshown",
+ /* capture = */ false,
+ event => event.target.id == "invalid-form-popup"
+ );
+ return document.getElementById("invalid-form-popup");
+}
+
+const HTML = `
+ <form action="">
+ <input name="text" type="text" placeholder="type here" autofocus required>
+ <input id="submit" type="submit">
+ </form>
+`;
+
+add_task(async function bug_1790128() {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: `data:text/html,${encodeURI(HTML)}`,
+ },
+ async function (aBrowser) {
+ let promisePopupShown = promiseValidityPopupShown();
+ await BrowserTestUtils.synthesizeMouseAtCenter("#submit", {}, aBrowser);
+ let popup = await promisePopupShown;
+ is(popup.state, "open", "Should be open");
+
+ let promisePopupHidden = BrowserTestUtils.waitForEvent(
+ popup,
+ "popuphidden"
+ );
+ promisePopupShown = promiseValidityPopupShown();
+
+ // This is written in a rather odd style because depending on whether
+ // panel animations are enabled we might be able to show the popup again
+ // after the first click or not. The point is that after one click the
+ // popup should've hid at least once, and after two the popup should've
+ // open again at least once.
+ await BrowserTestUtils.synthesizeMouseAtCenter("#submit", {}, aBrowser);
+ await promisePopupHidden;
+ await BrowserTestUtils.synthesizeMouseAtCenter("#submit", {}, aBrowser);
+ await promisePopupShown;
+ ok(true, "Should've shown the popup again");
+ }
+ );
+});
diff --git a/dom/base/test/browser_inputStream_structuredClone.js b/dom/base/test/browser_inputStream_structuredClone.js
new file mode 100644
index 0000000000..a022563ac0
--- /dev/null
+++ b/dom/base/test/browser_inputStream_structuredClone.js
@@ -0,0 +1,72 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const URIs = [
+ "about:about",
+ "http://example.com/browser/dom/base/test/empty.html",
+];
+
+async function runTest(input, url) {
+ let tab = BrowserTestUtils.addTab(gBrowser, url);
+ let browser = gBrowser.getBrowserForTab(tab);
+
+ await BrowserTestUtils.browserLoaded(browser);
+
+ let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ stream.setData(input, input.length);
+
+ let data = {
+ inputStream: stream,
+ };
+
+ is(
+ data.inputStream.available(),
+ input.length,
+ "The length of the inputStream matches: " + input.length
+ );
+
+ // FIXME: SpecialPowers.spawn currently crashes when trying to return
+ // values containing input streams.
+ /* eslint-disable no-shadow */
+ let dataBack = await ContentTask.spawn(browser, data, function (data) {
+ let dataBack = {
+ inputStream: data.inputStream,
+ check: true,
+ };
+
+ if (content.location.href.startsWith("about:")) {
+ dataBack.check =
+ data.inputStream instanceof
+ content.Components.interfaces.nsIInputStream;
+ }
+
+ return dataBack;
+ });
+ /* eslint-enable no-shadow */
+
+ ok(dataBack.check, "The inputStream is a nsIInputStream also on content.");
+ ok(
+ data.inputStream instanceof Ci.nsIInputStream,
+ "The original object was an inputStream"
+ );
+ ok(
+ dataBack.inputStream instanceof Ci.nsIInputStream,
+ "We have an inputStream back from the content."
+ );
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test() {
+ let a = "a";
+ for (let i = 0; i < 25; ++i) {
+ a += a;
+ }
+
+ for (let i = 0; i < URIs.length; ++i) {
+ await runTest("Hello world", URIs[i]);
+ await runTest(a, URIs[i]);
+ }
+});
diff --git a/dom/base/test/browser_messagemanager_loadprocessscript.js b/dom/base/test/browser_messagemanager_loadprocessscript.js
new file mode 100644
index 0000000000..16686dd566
--- /dev/null
+++ b/dom/base/test/browser_messagemanager_loadprocessscript.js
@@ -0,0 +1,193 @@
+function getBaseNumberOfProcesses() {
+ // We should have three processes for this test, the parent process and two
+ // content processes for the tabs craeted by this test.
+ let processCount = 3;
+
+ // If we run WebExtensions out-of-process (see bug 1190679), there might be
+ // additional processes for those, so let's add these to the base count to
+ // not have system WebExtensions cause test failures.
+ for (let i = 0; i < Services.ppmm.childCount; i++) {
+ if (
+ Services.ppmm.getChildAt(i).remoteType === E10SUtils.EXTENSION_REMOTE_TYPE
+ ) {
+ processCount += 1;
+ }
+ }
+
+ return processCount;
+}
+
+function checkBaseProcessCount(description) {
+ const baseProcessCount = getBaseNumberOfProcesses();
+ const { childCount } = Services.ppmm;
+ // With preloaded activity-stream, process count is a bit undeterministic, so
+ // allow for some variation
+ const extraCount = baseProcessCount + 1;
+ ok(
+ childCount === baseProcessCount || childCount === extraCount,
+ `${description} (${baseProcessCount} or ${extraCount})`
+ );
+}
+
+function processScript() {
+ /* eslint-env mozilla/process-script */
+ if (Services.cpmm !== this) {
+ dump("Test failed: wrong global object\n");
+ return;
+ }
+
+ this.cpmm = Services.cpmm;
+
+ addMessageListener("ProcessTest:Reply", function listener(msg) {
+ removeMessageListener("ProcessTest:Reply", listener);
+ sendAsyncMessage("ProcessTest:Finished");
+ });
+ sendSyncMessage("ProcessTest:Loaded");
+}
+var processScriptURL = "data:,(" + processScript.toString() + ").call(this)";
+
+function initTestScript() {
+ /* eslint-env mozilla/process-script */
+ let init = initialProcessData;
+ if (init.test123 != "hello") {
+ dump("Initial data incorrect\n");
+ return;
+ }
+
+ sendAsyncMessage("ProcessTest:InitGood", init.test456.get("hi"));
+}
+var initTestScriptURL = "data:,(" + initTestScript.toString() + ")()";
+
+var checkProcess = async function (mm) {
+ let { target } = await promiseMessage(mm, "ProcessTest:Loaded");
+ target.sendAsyncMessage("ProcessTest:Reply");
+ await promiseMessage(target, "ProcessTest:Finished");
+ ok(true, "Saw process finished");
+};
+
+function promiseMessage(messageManager, message) {
+ return new Promise(resolve => {
+ let listener = msg => {
+ messageManager.removeMessageListener(message, listener);
+ resolve(msg);
+ };
+
+ messageManager.addMessageListener(message, listener);
+ });
+}
+
+add_task(async function () {
+ // We want to count processes in this test, so let's disable the pre-allocated process manager.
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.ipc.processPrelaunch.enabled", false]],
+ });
+});
+
+add_task(async function () {
+ // This test is only relevant in e10s.
+ if (!gMultiProcessBrowser) {
+ return;
+ }
+
+ Services.ppmm.releaseCachedProcesses();
+
+ await SpecialPowers.pushPrefEnv({ set: [["dom.ipc.processCount", 5]] });
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.ipc.keepProcessesAlive.web", 5]],
+ });
+
+ let tabs = [];
+ for (let i = 0; i < 3; i++) {
+ tabs[i] = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "about:blank"
+ );
+ }
+
+ for (let i = 0; i < 3; i++) {
+ // FIXME: This should wait for the tab removal gets reflected to the
+ // process count (bug 1446726).
+ let sessionStorePromise = BrowserTestUtils.waitForSessionStoreUpdate(
+ tabs[i]
+ );
+ BrowserTestUtils.removeTab(tabs[i]);
+ await sessionStorePromise;
+ }
+
+ Services.ppmm.releaseCachedProcesses();
+ checkBaseProcessCount(
+ "Should get back to the base number of processes at this point"
+ );
+});
+
+// Test that loading a process script loads in all existing processes
+add_task(async function () {
+ let checks = [];
+ for (let i = 0; i < Services.ppmm.childCount; i++) {
+ checks.push(checkProcess(Services.ppmm.getChildAt(i)));
+ }
+
+ Services.ppmm.loadProcessScript(processScriptURL, false);
+ await Promise.all(checks);
+});
+
+// Test that loading a process script loads in new processes
+add_task(async function () {
+ // This test is only relevant in e10s
+ if (!gMultiProcessBrowser) {
+ return;
+ }
+
+ checkBaseProcessCount(
+ "Should still be at the base number of processes at this point"
+ );
+
+ // Load something in the main process
+ BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, "about:mozilla");
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+ let init = Services.ppmm.initialProcessData;
+ init.test123 = "hello";
+ init.test456 = new Map();
+ init.test456.set("hi", "bye");
+
+ // With no remote frames left we should be down to one process.
+ // However, stuff like remote thumbnails can cause a content
+ // process to exist nonetheless. This should be rare, though,
+ // so the test is useful most of the time.
+ if (Services.ppmm.childCount == 2) {
+ let mainMM = Services.ppmm.getChildAt(0);
+
+ let check = checkProcess(Services.ppmm);
+ Services.ppmm.loadProcessScript(processScriptURL, true);
+
+ // The main process should respond
+ await check;
+
+ check = checkProcess(Services.ppmm);
+ // Reset the default browser to start a new child process
+ gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, {
+ remoteType: E10SUtils.DEFAULT_REMOTE_TYPE,
+ });
+ BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, "about:blank");
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+ checkBaseProcessCount(
+ "Should be back to the base number of processes at this point"
+ );
+
+ // The new process should have responded
+ await check;
+
+ Services.ppmm.removeDelayedProcessScript(processScriptURL);
+
+ let childMM;
+ childMM = Services.ppmm.getChildAt(2);
+
+ childMM.loadProcessScript(initTestScriptURL, false);
+ let msg = await promiseMessage(childMM, "ProcessTest:InitGood");
+ is(msg.data, "bye", "initial process data was correct");
+ } else {
+ info("Unable to finish test entirely");
+ }
+});
diff --git a/dom/base/test/browser_messagemanager_targetframeloader.js b/dom/base/test/browser_messagemanager_targetframeloader.js
new file mode 100644
index 0000000000..62c8482add
--- /dev/null
+++ b/dom/base/test/browser_messagemanager_targetframeloader.js
@@ -0,0 +1,36 @@
+function frameScript() {
+ sendSyncMessage("Test:Message");
+ sendAsyncMessage("Test:Message");
+ sendAsyncMessage("Test:Done");
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ var newTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
+ gBrowser.selectedTab = newTab;
+
+ let browser = newTab.linkedBrowser;
+ let frameLoader = browser.frameLoader;
+ ok(frameLoader !== null, "frameLoader looks okay");
+
+ browser.messageManager.loadFrameScript(
+ "data:,(" + frameScript.toString() + ")()",
+ false
+ );
+
+ browser.messageManager.addMessageListener("Test:Message", msg => {
+ ok(msg.target === browser, "<browser> is correct");
+ ok(msg.targetFrameLoader === frameLoader, "frameLoader is correct");
+ ok(
+ browser.frameLoader === msg.targetFrameLoader,
+ "browser frameloader is correct"
+ );
+ });
+
+ browser.messageManager.addMessageListener("Test:Done", () => {
+ info("Finished");
+ gBrowser.removeCurrentTab();
+ finish();
+ });
+}
diff --git a/dom/base/test/browser_messagemanager_unload.js b/dom/base/test/browser_messagemanager_unload.js
new file mode 100644
index 0000000000..de8be528b3
--- /dev/null
+++ b/dom/base/test/browser_messagemanager_unload.js
@@ -0,0 +1,131 @@
+function frameScript() {
+ function eventHandler(e) {
+ if (!docShell) {
+ sendAsyncMessage("Test:Fail", "docShell is null");
+ }
+
+ sendAsyncMessage("Test:Event", [
+ e.type,
+ e.target === content.document,
+ e.eventPhase,
+ ]);
+ }
+
+ let outerID = content.docShell.outerWindowID;
+ function onOuterWindowDestroyed(subject, topic, data) {
+ if (docShell) {
+ sendAsyncMessage("Test:Fail", "docShell is non-null");
+ }
+
+ let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
+ sendAsyncMessage("Test:Event", ["outer-window-destroyed", id == outerID]);
+ if (id == outerID) {
+ Services.obs.removeObserver(
+ onOuterWindowDestroyed,
+ "outer-window-destroyed"
+ );
+ }
+ }
+
+ let url =
+ "https://example.com/browser/dom/base/test/file_messagemanager_unload.html";
+
+ content.location = url;
+ addEventListener(
+ "load",
+ e => {
+ if (e.target.location != url) {
+ return;
+ }
+
+ addEventListener("unload", eventHandler, false);
+ addEventListener("unload", eventHandler, true);
+ addEventListener("pagehide", eventHandler, false);
+ addEventListener("pagehide", eventHandler, true);
+ Services.obs.addObserver(
+ onOuterWindowDestroyed,
+ "outer-window-destroyed"
+ );
+
+ sendAsyncMessage("Test:Ready");
+ },
+ true
+ );
+}
+
+const EXPECTED = [
+ // Unload events on the BrowserChildGlobal. These come first so that the
+ // docshell is available.
+ ["unload", false, 2],
+ ["unload", false, 2],
+
+ // pagehide and unload events for the top-level page.
+ ["pagehide", true, 1],
+ ["pagehide", true, 3],
+ ["unload", true, 1],
+
+ // pagehide and unload events for the iframe.
+ ["pagehide", false, 1],
+ ["pagehide", false, 3],
+ ["unload", false, 1],
+
+ // outer-window-destroyed for both pages.
+ ["outer-window-destroyed", false],
+ ["outer-window-destroyed", true],
+];
+
+function test() {
+ waitForExplicitFinish();
+
+ var newTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
+ gBrowser.selectedTab = newTab;
+
+ let browser = newTab.linkedBrowser;
+ let frameLoader = browser.frameLoader;
+ ok(frameLoader !== null, "frameLoader looks okay");
+
+ browser.messageManager.loadFrameScript(
+ "data:,(" + frameScript.toString() + ")()",
+ false
+ );
+
+ browser.messageManager.addMessageListener(
+ "Test:Fail",
+ msg => {
+ ok(false, msg.data);
+ },
+ true
+ );
+
+ let index = 0;
+ browser.messageManager.addMessageListener(
+ "Test:Event",
+ msg => {
+ ok(msg.target === browser, "<browser> is correct");
+ ok(msg.targetFrameLoader === frameLoader, "frameLoader is correct");
+ ok(
+ browser.frameLoader === null,
+ "browser frameloader null during teardown"
+ );
+
+ info(JSON.stringify(msg.data));
+
+ is(
+ JSON.stringify(msg.data),
+ JSON.stringify(EXPECTED[index]),
+ "results match"
+ );
+ index++;
+
+ if (index == EXPECTED.length) {
+ finish();
+ }
+ },
+ true
+ );
+
+ browser.messageManager.addMessageListener("Test:Ready", () => {
+ info("Got ready message");
+ gBrowser.removeCurrentTab();
+ });
+}
diff --git a/dom/base/test/browser_multiple_popups.html b/dom/base/test/browser_multiple_popups.html
new file mode 100644
index 0000000000..6e0b85ea06
--- /dev/null
+++ b/dom/base/test/browser_multiple_popups.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<body>
+ <button onclick="openPopups();" id="openPopups">open popups</button>
+ <button onclick="openNestedPopups();" id="openNestedPopups">open tested popups</button>
+ <button onclick="openPopupAndClick();" id="openPopupAndClick">open popups and click</button>
+ <button onclick="closeAllWindows();" id="closeAllWindows">close all windows</button>
+ <button onclick="openPopupInFrame();" id="openPopupInFrame">open popup in frame</button>
+ <input type="text" id="input" />
+ <script>
+let windows = [];
+
+function openPopups() {
+ windows.push(window.open('empty.html', '_blank', 'width=100,height=100'));
+ windows.push(window.open('empty.html', '_blank', 'width=100,height=100'));
+}
+
+function openNestedPopups() {
+ var w = window.open('empty.html', '_blank', 'width=100,height=100');
+ windows.push(w);
+ windows.push(w.open('empty.html', '_blank', 'width=100,height=100'));
+}
+
+var recursion = false;
+function openPopupAndClick() {
+ windows.push(window.open('empty.html', '_blank', 'width=100,height=100'));
+ if (!recursion) {
+ recursion = true;
+ document.getElementById("openPopupAndClick").click();
+ }
+}
+
+function openPopupInFrame() {
+ let iframe = document.createElement("iframe");
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+ windows.push(iframe.contentWindow.open('empty.html', '_blank', 'width=100,height=100'));
+ iframe.remove();
+}
+
+function closeAllWindows() {
+ windows.forEach(w => {
+ try {
+ w.close();
+ } catch(e) {}
+ });
+}
+
+if (location.search.includes("openPopups")) {
+ let id = setInterval(() => {
+ if (document.getElementById('start')) {
+ clearInterval(id);
+ openPopups();
+ }
+ }, 500);
+}
+
+document.getElementById("input").onmouseup = _ => {
+ openPopups();
+}
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/browser_multiple_popups.js b/dom/base/test/browser_multiple_popups.js
new file mode 100644
index 0000000000..c50c246644
--- /dev/null
+++ b/dom/base/test/browser_multiple_popups.js
@@ -0,0 +1,296 @@
+/**
+ * In this test, we check that the content can't open more than one popup at a
+ * time (depending on "dom.allow_mulitple_popups" preference value).
+ */
+
+const TEST_DOMAIN = "https://example.net";
+const TEST_PATH = "/browser/dom/base/test/";
+const CHROME_DOMAIN = "chrome://mochitests/content";
+
+requestLongerTimeout(2);
+
+function promisePopups(count) {
+ let windows = [];
+ return new Promise(resolve => {
+ if (count == 0) {
+ resolve([]);
+ return;
+ }
+
+ let windowObserver = function (aSubject, aTopic, aData) {
+ if (aTopic != "domwindowopened") {
+ return;
+ }
+ windows.push(aSubject);
+ if (--count == 0) {
+ Services.ww.unregisterNotification(windowObserver);
+ SimpleTest.executeSoon(() => resolve(windows));
+ }
+ };
+ Services.ww.registerNotification(windowObserver);
+ });
+}
+
+async function withTestPage(popupCount, optionsOrCallback, callback) {
+ let options = optionsOrCallback;
+ if (!callback) {
+ callback = optionsOrCallback;
+ options = {};
+ }
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.block_multiple_popups", true],
+ ["dom.disable_open_during_load", true],
+ ],
+ });
+
+ let domain = options.chrome ? CHROME_DOMAIN : TEST_DOMAIN;
+ let tab = BrowserTestUtils.addTab(
+ gBrowser,
+ domain + TEST_PATH + "browser_multiple_popups.html" + (options.query || "")
+ );
+ gBrowser.selectedTab = tab;
+
+ let browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ let obs = promisePopups(popupCount);
+
+ await callback(browser);
+
+ let windows = await obs;
+ ok(true, `We had ${popupCount} windows.`);
+ for (let win of windows) {
+ if (win.document.readyState !== "complete") {
+ await BrowserTestUtils.waitForEvent(win, "load");
+ }
+ await BrowserTestUtils.closeWindow(win);
+ }
+ BrowserTestUtils.removeTab(tab);
+}
+
+function promisePopupsBlocked(browser, expectedCount) {
+ return SpecialPowers.spawn(browser, [expectedCount], count => {
+ return new content.Promise(resolve => {
+ content.addEventListener("DOMPopupBlocked", function cb() {
+ if (--count == 0) {
+ content.removeEventListener("DOMPopupBlocked", cb);
+ ok(true, "The popup has been blocked");
+ resolve();
+ }
+ });
+ });
+ });
+}
+
+function startOpeningTwoPopups(browser) {
+ return SpecialPowers.spawn(browser.browsingContext, [], () => {
+ let p = content.document.createElement("p");
+ p.setAttribute("id", "start");
+ content.document.body.appendChild(p);
+ });
+}
+
+add_task(async _ => {
+ info("All opened if the pref is off");
+ await withTestPage(2, async function (browser) {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.block_multiple_popups", false],
+ ["dom.disable_open_during_load", true],
+ ],
+ });
+
+ await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, browser);
+ });
+});
+
+add_task(async _ => {
+ info("2 window.open()s in a click event allowed because whitelisted domain.");
+
+ const uri = Services.io.newURI(TEST_DOMAIN);
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "popup",
+ Services.perms.ALLOW_ACTION
+ );
+
+ await withTestPage(2, async function (browser) {
+ await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, browser);
+ });
+
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+});
+
+add_task(async _ => {
+ info(
+ "2 window.open()s in a mouseup event allowed because whitelisted domain."
+ );
+
+ const uri = Services.io.newURI(TEST_DOMAIN);
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "popup",
+ Services.perms.ALLOW_ACTION
+ );
+
+ await withTestPage(2, async function (browser) {
+ await BrowserTestUtils.synthesizeMouseAtCenter("#input", {}, browser);
+ });
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+});
+
+add_task(async _ => {
+ info(
+ "2 window.open()s in a single click event: only the first one is allowed."
+ );
+
+ await withTestPage(1, async function (browser) {
+ let p = promisePopupsBlocked(browser, 1);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, browser);
+ await p;
+ });
+});
+
+add_task(async _ => {
+ info(
+ "2 window.open()s in a single mouseup event: only the first one is allowed."
+ );
+
+ await withTestPage(1, async function (browser) {
+ let p = promisePopupsBlocked(browser, 1);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#input", {}, browser);
+ await p;
+ });
+});
+
+add_task(async _ => {
+ info("2 window.open()s by non-event code: no windows allowed.");
+
+ await withTestPage(0, { query: "?openPopups" }, async function (browser) {
+ let p = promisePopupsBlocked(browser, 2);
+ await startOpeningTwoPopups(browser);
+ await p;
+ });
+});
+
+add_task(async _ => {
+ info("2 window.open()s by non-event code allowed by permission");
+ const uri = Services.io.newURI(TEST_DOMAIN);
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "popup",
+ Services.perms.ALLOW_ACTION
+ );
+
+ await withTestPage(2, { query: "?openPopups" }, async function (browser) {
+ await startOpeningTwoPopups(browser);
+ });
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+});
+
+add_task(async _ => {
+ info(
+ "1 window.open() executing another window.open(): only the first one is allowed."
+ );
+
+ await withTestPage(1, async function (browser) {
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#openNestedPopups",
+ {},
+ browser
+ );
+ });
+});
+
+add_task(async _ => {
+ info("window.open() and .click() on the element opening the window.");
+
+ await withTestPage(1, async function (browser) {
+ let p = promisePopupsBlocked(browser, 1);
+
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#openPopupAndClick",
+ {},
+ browser
+ );
+
+ await p;
+ });
+});
+
+add_task(async _ => {
+ info("All opened from chrome.");
+ await withTestPage(2, { chrome: true }, async function (browser) {
+ await BrowserTestUtils.synthesizeMouseAtCenter("#openPopups", {}, browser);
+ });
+});
+
+add_task(async function test_bug_1685056() {
+ info(
+ "window.open() from a blank iframe window during an event dispatched at the parent page: window should be allowed"
+ );
+
+ await withTestPage(1, async function (browser) {
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#openPopupInFrame",
+ {},
+ browser
+ );
+ });
+});
+
+add_task(async function test_bug_1689853() {
+ info("window.open() from a js bookmark (LOAD_FLAGS_ALLOW_POPUPS)");
+ await withTestPage(1, async function (browser) {
+ const URI =
+ "javascript:void(window.open('empty.html', '_blank', 'width=100,height=100'));";
+ window.openTrustedLinkIn(URI, "current", {
+ allowPopups: true,
+ inBackground: false,
+ allowInheritPrincipal: true,
+ });
+ });
+});
diff --git a/dom/base/test/browser_outline_refocus.js b/dom/base/test/browser_outline_refocus.js
new file mode 100644
index 0000000000..066c25de63
--- /dev/null
+++ b/dom/base/test/browser_outline_refocus.js
@@ -0,0 +1,65 @@
+const URL = `data:text/html,<a target="_blank" href="http://example.com">Click me</a>`;
+
+async function test_browser_outline_refocus(
+ aMessage,
+ aShouldFocusBeVisible,
+ aOpenTabCallback
+) {
+ await BrowserTestUtils.withNewTab(URL, async function (browser) {
+ let tab = gBrowser.getTabForBrowser(browser);
+ let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+
+ await aOpenTabCallback(browser);
+
+ info("waiting for new tab");
+ let newTab = await newTabPromise;
+
+ is(gBrowser.selectedTab, newTab, "Should've switched to the new tab");
+
+ info("switching back");
+ await BrowserTestUtils.switchTab(gBrowser, tab);
+
+ info("checking focus");
+ let [wasFocused, wasFocusVisible] = await SpecialPowers.spawn(
+ browser,
+ [],
+ () => {
+ let link = content.document.querySelector("a");
+ return [link.matches(":focus"), link.matches(":focus-visible")];
+ }
+ );
+
+ ok(wasFocused, "Link should be refocused");
+ is(wasFocusVisible, aShouldFocusBeVisible, aMessage);
+
+ info("closing tab");
+ await BrowserTestUtils.removeTab(newTab);
+ });
+}
+
+add_task(async function browser_outline_refocus_mouse() {
+ await test_browser_outline_refocus(
+ "Link shouldn't show outlines since it was originally focused by mouse",
+ false,
+ function (aBrowser) {
+ info("clicking on link");
+ return BrowserTestUtils.synthesizeMouseAtCenter("a", {}, aBrowser);
+ }
+ );
+});
+
+add_task(async function browser_outline_refocus_key() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["accessibility.tabfocus", 7]],
+ });
+
+ await test_browser_outline_refocus(
+ "Link should show outlines since it was originally focused by keyboard",
+ true,
+ function (aBrowser) {
+ info("Navigating via keyboard");
+ EventUtils.sendKey("tab");
+ EventUtils.sendKey("return");
+ }
+ );
+});
diff --git a/dom/base/test/browser_page_load_event_telemetry.js b/dom/base/test/browser_page_load_event_telemetry.js
new file mode 100644
index 0000000000..839e333d61
--- /dev/null
+++ b/dom/base/test/browser_page_load_event_telemetry.js
@@ -0,0 +1,46 @@
+"use strict";
+
+const { TelemetryTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryTestUtils.sys.mjs"
+);
+
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
+
+add_task(async function () {
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ waitForLoad: true,
+ });
+
+ let browser = tab.linkedBrowser;
+
+ // Reset event counts.
+ Services.telemetry.clearEvents();
+ TelemetryTestUtils.assertNumberOfEvents(0);
+
+ // Add checks for pageload ping and pageload event
+ let pingSubmitted = false;
+ GleanPings.pageload.testBeforeNextSubmit(reason => {
+ pingSubmitted = true;
+ Assert.equal(reason, "threshold");
+ let record = Glean.perf.pageLoad.testGetValue();
+ Assert.greaterOrEqual(
+ record.length,
+ 30,
+ "Should have at least 30 page load events"
+ );
+ });
+
+ // Perform page load 30 times to trigger the ping being sent
+ for (let i = 0; i < 30; i++) {
+ BrowserTestUtils.loadURIString(browser, "https://example.com");
+ await BrowserTestUtils.browserLoaded(browser);
+ }
+
+ await BrowserTestUtils.waitForCondition(
+ () => pingSubmitted,
+ "Page load ping should have been submitted."
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/dom/base/test/browser_pagehide_on_tab_close.js b/dom/base/test/browser_pagehide_on_tab_close.js
new file mode 100644
index 0000000000..4db890aa57
--- /dev/null
+++ b/dom/base/test/browser_pagehide_on_tab_close.js
@@ -0,0 +1,21 @@
+function test() {
+ waitForExplicitFinish();
+
+ var tab = BrowserTestUtils.addTab(gBrowser);
+ gBrowser.selectedTab = tab;
+
+ tab.linkedBrowser.addEventListener(
+ "load",
+ function () {
+ tab.linkedBrowser.addEventListener("pagehide", function () {
+ ok(true, "got page hide event");
+ finish();
+ });
+
+ executeSoon(() => {
+ gBrowser.removeTab(tab);
+ });
+ },
+ { capture: true, once: true }
+ );
+}
diff --git a/dom/base/test/browser_promiseDocumentFlushed.js b/dom/base/test/browser_promiseDocumentFlushed.js
new file mode 100644
index 0000000000..1df8f7af55
--- /dev/null
+++ b/dom/base/test/browser_promiseDocumentFlushed.js
@@ -0,0 +1,292 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Dirties style and layout on the current browser window.
+ *
+ * @param {Number} Optional factor by which to modify the DOM. Useful for
+ * when multiple calls to dirtyTheDOM may occur, and you need them
+ * to dirty the DOM differently from one another. If you only need
+ * to dirty the DOM once, this can be omitted.
+ */
+function dirtyStyleAndLayout(factor = 1) {
+ gNavToolbox.style.padding = factor + "px";
+}
+
+/**
+ * Dirties style of the current browser window, but NOT layout.
+ */
+function dirtyStyle() {
+ gNavToolbox.style.color = "red";
+}
+
+const gWindowUtils = window.windowUtils;
+
+/**
+ * Asserts that no style or layout flushes are required by the
+ * current window.
+ */
+function assertNoFlushesRequired() {
+ Assert.ok(
+ !gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
+ "No style flushes are required."
+ );
+ Assert.ok(
+ !gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
+ "No layout flushes are required."
+ );
+}
+
+/**
+ * Asserts that the DOM has been dirtied, and so style and layout flushes
+ * are required.
+ */
+function assertFlushesRequired() {
+ Assert.ok(
+ gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE),
+ "Style flush required."
+ );
+ Assert.ok(
+ gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT),
+ "Layout flush required."
+ );
+}
+
+/**
+ * Removes style changes from dirtyTheDOM() from the browser window,
+ * and resolves once the refresh driver ticks.
+ */
+async function cleanTheDOM() {
+ gNavToolbox.style.padding = "";
+ gNavToolbox.style.color = "";
+ await window.promiseDocumentFlushed(() => {});
+}
+
+add_setup(async function () {
+ registerCleanupFunction(cleanTheDOM);
+});
+
+/**
+ * Tests that if the DOM is dirty, that promiseDocumentFlushed will
+ * resolve once layout and style have been flushed.
+ */
+add_task(async function test_basic() {
+ info("Dirtying style / layout");
+ dirtyStyleAndLayout();
+ assertFlushesRequired();
+
+ info("Waiting");
+ await window.promiseDocumentFlushed(() => {});
+ assertNoFlushesRequired();
+
+ info("Dirtying style");
+ dirtyStyle();
+ assertFlushesRequired();
+
+ info("Waiting");
+ await window.promiseDocumentFlushed(() => {});
+ assertNoFlushesRequired();
+
+ // The DOM should be clean already, but we'll do this anyway to isolate
+ // failures from other tests.
+ info("Cleaning up");
+ await cleanTheDOM();
+});
+
+/**
+ * Test that values returned by the callback passed to promiseDocumentFlushed
+ * get passed down through the Promise resolution.
+ */
+add_task(async function test_can_get_results_from_callback() {
+ const NEW_PADDING = "2px";
+
+ gNavToolbox.style.padding = NEW_PADDING;
+
+ assertFlushesRequired();
+
+ let paddings = await window.promiseDocumentFlushed(() => {
+ let style = window.getComputedStyle(gNavToolbox);
+ return {
+ left: style.paddingLeft,
+ right: style.paddingRight,
+ top: style.paddingTop,
+ bottom: style.paddingBottom,
+ };
+ });
+
+ for (let prop in paddings) {
+ Assert.equal(paddings[prop], NEW_PADDING, "Got expected padding");
+ }
+
+ await cleanTheDOM();
+
+ gNavToolbox.style.padding = NEW_PADDING;
+
+ assertFlushesRequired();
+
+ let rect = await window.promiseDocumentFlushed(() => {
+ let observer = {
+ reflow() {
+ Assert.ok(false, "A reflow should not have occurred.");
+ },
+ reflowInterruptible() {},
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIReflowObserver",
+ "nsISupportsWeakReference",
+ ]),
+ };
+
+ let docShell = window.docShell;
+ docShell.addWeakReflowObserver(observer);
+
+ let toolboxRect = gNavToolbox.getBoundingClientRect();
+
+ docShell.removeWeakReflowObserver(observer);
+ return toolboxRect;
+ });
+
+ // The actual values of this rect aren't super important for
+ // the purposes of this test - we just want to know that a valid
+ // rect was returned, so checking for properties being greater than
+ // 0 is sufficient.
+ for (let property of ["width", "height"]) {
+ Assert.ok(
+ rect[property] > 0,
+ `Rect property ${property} > 0 (${rect[property]})`
+ );
+ }
+
+ await cleanTheDOM();
+});
+
+/**
+ * Test that if promiseDocumentFlushed is requested on a window
+ * that closes before it gets a chance to do a refresh driver
+ * tick, the promiseDocumentFlushed Promise is still resolved, and
+ * the callback is still called.
+ */
+add_task(async function test_resolved_in_window_close() {
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+
+ await win.promiseDocumentFlushed(() => {});
+
+ // Use advanceTimeAndRefresh to pause paints in the window:
+ let utils = win.windowUtils;
+ utils.advanceTimeAndRefresh(0);
+
+ win.gNavToolbox.style.padding = "5px";
+
+ const EXPECTED = 1234;
+ let promise = win.promiseDocumentFlushed(() => {
+ // Despite the window not painting before closing, this
+ // callback should be fired when the window gets torn
+ // down and should stil be able to return a result.
+ return EXPECTED;
+ });
+
+ await BrowserTestUtils.closeWindow(win);
+ Assert.equal(await promise, EXPECTED);
+});
+
+/**
+ * Test that re-entering promiseDocumentFlushed is not possible
+ * from within a promiseDocumentFlushed callback. Doing so will
+ * result in the outer Promise rejecting with InvalidStateError.
+ */
+add_task(async function test_reentrancy() {
+ dirtyStyleAndLayout();
+ assertFlushesRequired();
+
+ let promise = window.promiseDocumentFlushed(() => {
+ return window.promiseDocumentFlushed(() => {
+ Assert.ok(false, "Should never run this.");
+ });
+ });
+
+ await Assert.rejects(promise, ex => ex.name == "InvalidStateError");
+});
+
+/**
+ * Tests the expected execution order of a series of promiseDocumentFlushed
+ * calls, their callbacks, and the resolutions of their Promises.
+ *
+ * When multiple promiseDocumentFlushed callbacks are queued, the callbacks
+ * should always been run first before any of the Promises are resolved.
+ *
+ * The callbacks should run in the order that they were queued in via
+ * promiseDocumentFlushed. The Promise resolutions should similarly run
+ * in the order that promiseDocumentFlushed was called in.
+ */
+add_task(async function test_execution_order() {
+ let result = [];
+
+ dirtyStyleAndLayout(1);
+ let promise1 = window
+ .promiseDocumentFlushed(() => {
+ result.push(0);
+ })
+ .then(() => {
+ result.push(2);
+ });
+
+ let promise2 = window
+ .promiseDocumentFlushed(() => {
+ result.push(1);
+ })
+ .then(() => {
+ result.push(3);
+ });
+
+ await Promise.all([promise1, promise2]);
+
+ Assert.equal(result.length, 4, "Should have run all callbacks and Promises.");
+
+ let promise3 = window
+ .promiseDocumentFlushed(() => {
+ result.push(4);
+ })
+ .then(() => {
+ result.push(6);
+ });
+
+ let promise4 = window
+ .promiseDocumentFlushed(() => {
+ result.push(5);
+ })
+ .then(() => {
+ result.push(7);
+ });
+
+ await Promise.all([promise3, promise4]);
+
+ Assert.equal(result.length, 8, "Should have run all callbacks and Promises.");
+
+ for (let i = 0; i < result.length; ++i) {
+ Assert.equal(
+ result[i],
+ i,
+ "Callbacks and Promises should have run in the expected order."
+ );
+ }
+
+ await cleanTheDOM();
+});
+
+/**
+ * Tests that modifying the DOM within a promiseDocumentFlushed callback
+ * will result in the Promise being rejected.
+ */
+add_task(async function test_reject_on_modification() {
+ dirtyStyleAndLayout(1);
+ assertFlushesRequired();
+
+ let promise = window.promiseDocumentFlushed(() => {
+ dirtyStyleAndLayout(2);
+ });
+
+ await Assert.rejects(promise, /NoModificationAllowedError/);
+
+ await cleanTheDOM();
+});
diff --git a/dom/base/test/browser_refresh_content.js b/dom/base/test/browser_refresh_content.js
new file mode 100644
index 0000000000..0ff61db423
--- /dev/null
+++ b/dom/base/test/browser_refresh_content.js
@@ -0,0 +1,127 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * Ensures resources can still be fetched without validation
+ */
+
+const CONTENT_URL =
+ "http://www.example.com/browser/dom/base/test/file_browser_refresh_content.html";
+
+async function run_test_browser_refresh(forceRevalidate) {
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: CONTENT_URL,
+ waitForLoad: true,
+ /* Ensures each run is started with a fresh state */
+ forceNewProcess: true,
+ });
+
+ let originalAttributes = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ async () => {
+ let result = content.document.getElementById("result");
+ await ContentTaskUtils.waitForCondition(() => {
+ return (
+ result.getAttribute("imageDataURL") &&
+ result.getAttribute("iframeContent") &&
+ result.getAttribute("expiredResourceCacheControl")
+ );
+ });
+ return {
+ imageDataURL: result.getAttribute("imageDataURL"),
+ iframeContent: result.getAttribute("iframeContent"),
+ expiredResourceCacheControl: result.getAttribute(
+ "expiredResourceCacheControl"
+ ),
+ };
+ }
+ );
+
+ let imageDataURL = originalAttributes.imageDataURL;
+ let expiredResourceCacheControl =
+ originalAttributes.expiredResourceCacheControl;
+
+ is(
+ originalAttributes.iframeContent,
+ "first load",
+ "Iframe is loaded with the initial content"
+ );
+
+ tab.linkedBrowser.reload();
+
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ let attributes = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ async () => {
+ let result = content.document.getElementById("result");
+
+ await ContentTaskUtils.waitForCondition(() => {
+ return (
+ result.getAttribute("imageDataURL") &&
+ result.getAttribute("expiredResourceCacheControl") &&
+ result.getAttribute("nonCacheableResourceCompleted")
+ );
+ });
+
+ return {
+ iframeContent: result.getAttribute("iframeContent"),
+ imageDataURL: result.getAttribute("imageDataURL"),
+ expiredResourceCacheControl: result.getAttribute(
+ "expiredResourceCacheControl"
+ ),
+ nonCacheableResourceCompleted: result.getAttribute(
+ "nonCacheableResourceCompleted"
+ ),
+ };
+ }
+ );
+
+ is(
+ attributes.iframeContent,
+ "second load",
+ "Iframe should always be revalidated"
+ );
+
+ if (!forceRevalidate) {
+ ok(attributes.imageDataURL === imageDataURL, "Image should use cache");
+ } else {
+ ok(attributes.imageDataURL !== imageDataURL, "Image should be revalidated");
+ }
+
+ if (!forceRevalidate) {
+ ok(
+ attributes.expiredResourceCacheControl === expiredResourceCacheControl,
+ "max-age shouldn't be changed after reload because it didn't revalidate"
+ );
+ } else {
+ ok(
+ attributes.expiredResourceCacheControl !== expiredResourceCacheControl,
+ "max-age should be changed after reload because it got revalidated"
+ );
+ }
+
+ is(
+ attributes.nonCacheableResourceCompleted,
+ "true",
+ "Non cacheable resource should still be loaded"
+ );
+
+ await BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test_browser_refresh() {
+ Services.prefs.setBoolPref(
+ "browser.soft_reload.only_force_validate_top_level_document",
+ true
+ );
+ await run_test_browser_refresh(false);
+ Services.prefs.setBoolPref(
+ "browser.soft_reload.only_force_validate_top_level_document",
+ false
+ );
+ await run_test_browser_refresh(true);
+});
diff --git a/dom/base/test/browser_state_notifications.js b/dom/base/test/browser_state_notifications.js
new file mode 100644
index 0000000000..e2b600465b
--- /dev/null
+++ b/dom/base/test/browser_state_notifications.js
@@ -0,0 +1,193 @@
+/* globals Components: true, Promise: true, gBrowser: true, Test: true,
+ info: true, is: true, window: true, waitForExplicitFinish: true,
+ finish: true, ok: true*/
+
+"use strict";
+
+const { addObserver, removeObserver } = Cc[
+ "@mozilla.org/observer-service;1"
+].getService(Ci.nsIObserverService);
+const { openWindow } = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(
+ Ci.nsIWindowWatcher
+);
+
+const Test = routine => () => {
+ waitForExplicitFinish();
+ routine().then(finish, error => {
+ ok(false, error);
+ finish();
+ });
+};
+
+// Returns promise for the observer notification subject for
+// the given topic. If `receive("foo")` is called `n` times
+// nth promise is resolved on an `nth` "foo" notification.
+const receive = (topic, p, syncCallback) => {
+ return new Promise((resolve, reject) => {
+ const { queue } = receive;
+ const timeout = () => {
+ queue.splice(queue.indexOf(resolve) - 1, 2);
+ reject(new Error("Timeout"));
+ };
+
+ const observer = {
+ observe: subject => {
+ // Browser loads bunch of other documents that we don't care
+ // about so we let allow filtering notifications via `p` function.
+ if (p && !p(subject)) {
+ return;
+ }
+ // If observer is a first one with a given `topic`
+ // in a queue resolve promise and take it off the queue
+ // otherwise keep waiting.
+ const index = queue.indexOf(topic);
+ if (queue.indexOf(resolve) === index + 1) {
+ removeObserver(observer, topic);
+ clearTimeout(id, reject);
+ queue.splice(index, 2);
+ // Some tests need to be executed synchronously when the event is fired.
+ if (syncCallback) {
+ syncCallback(subject);
+ }
+ resolve(subject);
+ }
+ },
+ };
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ const id = setTimeout(timeout, 90000);
+ addObserver(observer, topic, false);
+ queue.push(topic, resolve);
+ });
+};
+receive.queue = [];
+
+const openTab = uri =>
+ (gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, uri));
+
+// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+const isData = document => document.URL.startsWith("data:");
+
+const uri1 = "data:text/html;charset=utf-8,<h1>1</h1>";
+// For whatever reason going back on load event doesn't work so timeout it is :(
+const uri2 =
+ "data:text/html;charset=utf-8,<h1>2</h1><script>setTimeout(SpecialPowers.wrap(window).back,100)</script>";
+const uri3 = "data:text/html;charset=utf-8,<h1>3</h1>";
+
+const uri4 = "chrome://browser/content/license.html";
+
+const test = Test(async function () {
+ let documentInteractive = receive(
+ "content-document-interactive",
+ isData,
+ d => {
+ // This test is executed synchronously when the event is received.
+ is(d.readyState, "interactive", "document is interactive");
+ is(d.URL, uri1, "document.URL matches tab url");
+ }
+ );
+ let documentLoaded = receive("content-document-loaded", isData);
+ let pageShown = receive("content-page-shown", isData);
+
+ info("open: uri#1");
+ const tab1 = openTab(uri1);
+ const browser1 = gBrowser.getBrowserForTab(tab1);
+
+ let interactiveDocument1 = await documentInteractive;
+
+ let loadedDocument1 = await documentLoaded;
+ is(loadedDocument1.readyState, "complete", "document is loaded");
+ is(interactiveDocument1, loadedDocument1, "interactive document is loaded");
+
+ let shownPage = await pageShown;
+ is(interactiveDocument1, shownPage, "loaded document is shown");
+
+ // Wait until history entry is created before loading new uri.
+ await receive("sessionstore-state-write-complete");
+
+ info("load uri#2");
+
+ documentInteractive = receive("content-document-interactive", isData, d => {
+ // This test is executed synchronously when the event is received.
+ is(d.readyState, "interactive", "document is interactive");
+ is(d.URL, uri2, "document.URL matches URL loaded");
+ });
+ documentLoaded = receive("content-document-loaded", isData);
+ pageShown = receive("content-page-shown", isData);
+ let pageHidden = receive("content-page-hidden", isData);
+
+ BrowserTestUtils.loadURIString(browser1, uri2);
+
+ let hiddenPage = await pageHidden;
+ is(interactiveDocument1, hiddenPage, "loaded document is hidden");
+
+ let interactiveDocument2 = await documentInteractive;
+
+ let loadedDocument2 = await documentLoaded;
+ is(loadedDocument2.readyState, "complete", "document is loaded");
+ is(interactiveDocument2, loadedDocument2, "interactive document is loaded");
+
+ shownPage = await pageShown;
+ is(interactiveDocument2, shownPage, "loaded document is shown");
+
+ info("go back to uri#1");
+
+ documentInteractive = receive("content-document-interactive", isData, d => {
+ // This test is executed synchronously when the event is received.
+ is(d.readyState, "interactive", "document is interactive");
+ is(d.URL, uri3, "document.URL matches URL loaded");
+ });
+ documentLoaded = receive("content-document-loaded", isData);
+ pageShown = receive("content-page-shown", isData);
+ pageHidden = receive("content-page-hidden", isData);
+
+ hiddenPage = await pageHidden;
+ is(interactiveDocument2, hiddenPage, "new document is hidden");
+
+ shownPage = await pageShown;
+ is(interactiveDocument1, shownPage, "previous document is shown");
+
+ info("load uri#3");
+
+ BrowserTestUtils.loadURIString(browser1, uri3);
+
+ pageShown = receive("content-page-shown", isData);
+
+ let interactiveDocument3 = await documentInteractive;
+
+ let loadedDocument3 = await documentLoaded;
+ is(loadedDocument3.readyState, "complete", "document is loaded");
+ is(interactiveDocument3, loadedDocument3, "interactive document is loaded");
+
+ shownPage = await pageShown;
+ is(interactiveDocument3, shownPage, "previous document is shown");
+
+ gBrowser.removeTab(tab1);
+
+ info("load chrome uri");
+
+ const tab2 = openTab(uri4);
+ documentInteractive = receive("chrome-document-interactive", null, d => {
+ // This test is executed synchronously when the event is received.
+ is(d.readyState, "interactive", "document is interactive");
+ is(d.URL, uri4, "document.URL matches URL loaded");
+ });
+ documentLoaded = receive("chrome-document-loaded");
+ pageShown = receive("chrome-page-shown");
+
+ const interactiveDocument4 = await documentInteractive;
+
+ let loadedDocument4 = await documentLoaded;
+ is(loadedDocument4.readyState, "complete", "document is loaded");
+ is(interactiveDocument4, loadedDocument4, "interactive document is loaded");
+
+ shownPage = await pageShown;
+ is(interactiveDocument4, shownPage, "loaded chrome document is shown");
+
+ pageHidden = receive("chrome-page-hidden");
+ gBrowser.removeTab(tab2);
+
+ hiddenPage = await pageHidden;
+ is(interactiveDocument4, hiddenPage, "chrome document hidden");
+});
diff --git a/dom/base/test/browser_timeout_throttling_with_audio_playback.js b/dom/base/test/browser_timeout_throttling_with_audio_playback.js
new file mode 100644
index 0000000000..89be64f656
--- /dev/null
+++ b/dom/base/test/browser_timeout_throttling_with_audio_playback.js
@@ -0,0 +1,73 @@
+// The tab closing code leaves an uncaught rejection. This test has been
+// whitelisted until the issue is fixed.
+if (!gMultiProcessBrowser) {
+ const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+ );
+ PromiseTestUtils.expectUncaughtRejection(/is no longer, usable/);
+}
+
+const kBaseURI = "http://mochi.test:8888/browser/dom/base/test/empty.html";
+var testURLs = [
+ "http://mochi.test:8888/browser/dom/base/test/file_audioLoop.html",
+ "http://mochi.test:8888/browser/dom/base/test/file_audioLoopInIframe.html",
+ "http://mochi.test:8888/browser/dom/base/test/file_webaudio_startstop.html",
+];
+
+// We want to ensure that while audio is being played back, a background tab is
+// treated the same as a foreground tab as far as timeout throttling is concerned.
+// So we use a 100,000 second minimum timeout value for background tabs. This
+// means that in case the test fails, it will time out in practice, but just for
+// sanity the test condition ensures that the observed timeout delay falls in
+// this range.
+const kMinTimeoutBackground = 100 * 1000 * 1000;
+
+const kDelay = 10;
+
+async function runTest(url) {
+ let currentTab = gBrowser.selectedTab;
+ let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kBaseURI);
+ let newBrowser = gBrowser.getBrowserForTab(newTab);
+
+ // Wait for the UI to indicate that audio is being played back.
+ let promise = BrowserTestUtils.waitForAttribute(
+ "soundplaying",
+ newTab,
+ "true"
+ );
+ BrowserTestUtils.loadURIString(newBrowser, url);
+ await promise;
+
+ // Put the tab in the background.
+ await BrowserTestUtils.switchTab(gBrowser, currentTab);
+
+ let timeout = await SpecialPowers.spawn(
+ newBrowser,
+ [kDelay],
+ function (delay) {
+ return new Promise(resolve => {
+ let before = new Date();
+ content.window.setTimeout(function () {
+ let after = new Date();
+ resolve(after - before);
+ }, delay);
+ });
+ }
+ );
+ ok(timeout <= kMinTimeoutBackground, `Got the correct timeout (${timeout})`);
+
+ // All done.
+ BrowserTestUtils.removeTab(newTab);
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.min_background_timeout_value", kMinTimeoutBackground]],
+ });
+});
+
+add_task(async function test() {
+ for (var url of testURLs) {
+ await runTest(url);
+ }
+});
diff --git a/dom/base/test/browser_use_counters.js b/dom/base/test/browser_use_counters.js
new file mode 100644
index 0000000000..b18d6aa06c
--- /dev/null
+++ b/dom/base/test/browser_use_counters.js
@@ -0,0 +1,348 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
+
+requestLongerTimeout(2);
+
+const gHttpTestRoot = "https://example.com/browser/dom/base/test/";
+
+/**
+ * Enable local telemetry recording for the duration of the tests.
+ */
+var gOldContentCanRecord = false;
+var gOldParentCanRecord = false;
+add_task(async function test_initialize() {
+ let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(
+ Ci.nsITelemetry
+ );
+ gOldParentCanRecord = Telemetry.canRecordExtended;
+ Telemetry.canRecordExtended = true;
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ // Because canRecordExtended is a per-process variable, we need to make sure
+ // that all of the pages load in the same content process. Limit the number
+ // of content processes to at most 1 (or 0 if e10s is off entirely).
+ ["dom.ipc.processCount", 1],
+ ["layout.css.use-counters.enabled", true],
+ ["layout.css.use-counters-unimplemented.enabled", true],
+ ],
+ });
+
+ gOldContentCanRecord = await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [],
+ function () {
+ let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(
+ Ci.nsITelemetry
+ );
+ let old = telemetry.canRecordExtended;
+ telemetry.canRecordExtended = true;
+ return old;
+ }
+ );
+ info("canRecord for content: " + gOldContentCanRecord);
+});
+
+add_task(async function () {
+ const TESTS = [
+ // Check that use counters are incremented by SVGs loaded directly in iframes.
+ {
+ type: "iframe",
+ filename: "file_use_counter_svg_getElementById.svg",
+ counters: [{ name: "SVGSVGELEMENT_GETELEMENTBYID" }],
+ },
+ {
+ type: "iframe",
+ filename: "file_use_counter_svg_currentScale.svg",
+ counters: [
+ { name: "SVGSVGELEMENT_CURRENTSCALE_getter" },
+ { name: "SVGSVGELEMENT_CURRENTSCALE_setter" },
+ ],
+ },
+
+ {
+ type: "iframe",
+ filename: "file_use_counter_style.html",
+ counters: [
+ // Check for longhands.
+ { name: "CSS_PROPERTY_BackgroundImage" },
+ // Check for shorthands.
+ { name: "CSS_PROPERTY_Padding" },
+ // Check for aliases.
+ { name: "CSS_PROPERTY_MozTransform" },
+ // Check for counted unknown properties.
+ { name: "CSS_PROPERTY_WebkitPaddingStart" },
+ ],
+ },
+
+ // Check that even loads from the imglib cache update use counters. The
+ // images should still be there, because we just loaded them in the last
+ // set of tests. But we won't get updated counts for the document
+ // counters, because we won't be re-parsing the SVG documents.
+ {
+ type: "iframe",
+ filename: "file_use_counter_svg_getElementById.svg",
+ counters: [{ name: "SVGSVGELEMENT_GETELEMENTBYID" }],
+ check_documents: false,
+ },
+ {
+ type: "iframe",
+ filename: "file_use_counter_svg_currentScale.svg",
+ counters: [
+ { name: "SVGSVGELEMENT_CURRENTSCALE_getter" },
+ { name: "SVGSVGELEMENT_CURRENTSCALE_setter" },
+ ],
+ check_documents: false,
+ },
+
+ // Check that use counters are incremented by SVGs loaded as images.
+ // Note that SVG images are not permitted to execute script, so we can only
+ // check for properties here.
+ {
+ type: "img",
+ filename: "file_use_counter_svg_getElementById.svg",
+ counters: [{ name: "CSS_PROPERTY_Fill" }],
+ },
+ {
+ type: "img",
+ filename: "file_use_counter_svg_currentScale.svg",
+ counters: [{ name: "CSS_PROPERTY_Fill" }],
+ },
+
+ // Check that use counters are incremented by directly loading SVGs
+ // that reference patterns defined in another SVG file.
+ {
+ type: "direct",
+ filename: "file_use_counter_svg_fill_pattern.svg",
+ counters: [{ name: "CSS_PROPERTY_FillOpacity", xfail: true }],
+ },
+
+ // Check that use counters are incremented by directly loading SVGs
+ // that reference patterns defined in the same file or in data: URLs.
+ {
+ type: "direct",
+ filename: "file_use_counter_svg_fill_pattern_internal.svg",
+ counters: [{ name: "CSS_PROPERTY_FillOpacity" }],
+ },
+
+ // Check that use counters are incremented in a display:none iframe.
+ {
+ type: "undisplayed-iframe",
+ filename: "file_use_counter_svg_currentScale.svg",
+ counters: [{ name: "SVGSVGELEMENT_CURRENTSCALE_getter" }],
+ },
+
+ // Check that a document that comes out of the bfcache reports any new use
+ // counters recorded on it.
+ {
+ type: "direct",
+ filename: "file_use_counter_bfcache.html",
+ waitForExplicitFinish: true,
+ counters: [{ name: "SVGSVGELEMENT_GETELEMENTBYID" }],
+ },
+
+ // // data: URLs don't correctly propagate to their referring document yet.
+ // {
+ // type: "direct",
+ // filename: "file_use_counter_svg_fill_pattern_data.svg",
+ // counters: [
+ // { name: "PROPERTY_FILL_OPACITY" },
+ // ],
+ // },
+ ];
+
+ for (let test of TESTS) {
+ let file = test.filename;
+ info(`checking ${file} (${test.type})`);
+
+ let newTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
+ gBrowser.selectedTab = newTab;
+ newTab.linkedBrowser.stop();
+
+ // Hold on to the current values of the telemetry histograms we're
+ // interested in.
+ let before = await grabHistogramsFromContent(
+ test.counters.map(c => c.name)
+ );
+
+ // Load the test file in the new tab, either directly or via
+ // file_use_counter_outer{,_display_none}.html, depending on the test type.
+ let url, targetElement;
+ switch (test.type) {
+ case "iframe":
+ url = gHttpTestRoot + "file_use_counter_outer.html";
+ targetElement = "content";
+ break;
+ case "undisplayed-iframe":
+ url = gHttpTestRoot + "file_use_counter_outer_display_none.html";
+ targetElement = "content";
+ break;
+ case "img":
+ url = gHttpTestRoot + "file_use_counter_outer.html";
+ targetElement = "display";
+ break;
+ case "direct":
+ url = gHttpTestRoot + file;
+ targetElement = null;
+ break;
+ default:
+ throw `unexpected type ${test.type}`;
+ }
+
+ BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, url);
+ await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+ if (test.waitForExplicitFinish) {
+ if (test.type != "direct") {
+ throw new Error(
+ `cannot use waitForExplicitFinish with test type ${test.type}`
+ );
+ }
+
+ // Wait until the tab changes its hash to indicate it has finished.
+ await BrowserTestUtils.waitForLocationChange(gBrowser, url + "#finished");
+ }
+
+ if (targetElement) {
+ // Inject our desired file into the target element of the newly-loaded page.
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [{ file, targetElement }],
+ function (opts) {
+ let target = content.document.getElementById(opts.targetElement);
+ target.src = opts.file;
+
+ return new Promise(resolve => {
+ let listener = event => {
+ event.target.removeEventListener("load", listener, true);
+ resolve();
+ };
+ target.addEventListener("load", listener, true);
+ });
+ }
+ );
+ }
+
+ // Tear down the page.
+ let tabClosed = BrowserTestUtils.waitForTabClosing(newTab);
+ gBrowser.removeTab(newTab);
+ await tabClosed;
+
+ // Grab histograms again.
+ let after = await grabHistogramsFromContent(
+ test.counters.map(c => c.name),
+ before.sentinel
+ );
+
+ // Compare before and after.
+ for (let counter of test.counters) {
+ let name = counter.name;
+ let value = counter.value ?? 1;
+ if (!counter.xfail) {
+ is(
+ after.page[name],
+ before.page[name] + value,
+ `page counts for ${name} after are correct`
+ );
+ is(
+ after.document[name],
+ before.document[name] + value,
+ `document counts for ${name} after are correct`
+ );
+ }
+ }
+
+ if (test.check_documents ?? true) {
+ ok(
+ after.toplevel_docs >= before.toplevel_docs + 1,
+ "top level destroyed document counts are correct"
+ );
+ // 2 documents for "img" tests: one for the outer html page containing the
+ // <img> element, and one for the SVG image itself.
+ ok(
+ after.docs >= before.docs + (test.type == "img" ? 2 : 1),
+ "destroyed document counts are correct"
+ );
+ }
+ }
+});
+
+add_task(async function () {
+ let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(
+ Ci.nsITelemetry
+ );
+ Telemetry.canRecordExtended = gOldParentCanRecord;
+
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [{ oldCanRecord: gOldContentCanRecord }],
+ async function (arg) {
+ await new Promise(resolve => {
+ let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(
+ Ci.nsITelemetry
+ );
+ telemetry.canRecordExtended = arg.oldCanRecord;
+ resolve();
+ });
+ }
+ );
+});
+
+async function grabHistogramsFromContent(names, prev_sentinel = null) {
+ // We don't have any way to get a notification when telemetry from the
+ // document that was just closed has been reported. So instead, we
+ // repeatedly poll for telemetry until we see that a specific use counter
+ // histogram (CSS_PROPERTY_MarkerMid, the "sentinel") that likely is not
+ // used by any other document that's open has been incremented.
+ let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(
+ Ci.nsITelemetry
+ );
+ let gatheredHistograms;
+ return BrowserTestUtils.waitForCondition(
+ function () {
+ // Document use counters are reported in the content process (when e10s
+ // is enabled), and page use counters are reported in the parent process.
+ let snapshots = telemetry.getSnapshotForHistograms("main", false);
+ let checkGet = probe => {
+ // When e10s is disabled, all histograms are reported in the parent
+ // process. Otherwise, all page use counters are reported in the parent
+ // and document use counters are reported in the content process.
+ let process =
+ !Services.appinfo.browserTabsRemoteAutostart ||
+ probe.endsWith("_PAGE") ||
+ probe == "TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED"
+ ? "parent"
+ : "content";
+ return snapshots[process][probe] ? snapshots[process][probe].sum : 0;
+ };
+ let page = Object.fromEntries(
+ names.map(name => [name, checkGet(`USE_COUNTER2_${name}_PAGE`)])
+ );
+ let document = Object.fromEntries(
+ names.map(name => [name, checkGet(`USE_COUNTER2_${name}_DOCUMENT`)])
+ );
+ gatheredHistograms = {
+ page,
+ document,
+ docs: checkGet("CONTENT_DOCUMENTS_DESTROYED"),
+ toplevel_docs: checkGet("TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED"),
+ sentinel: {
+ doc: checkGet("USE_COUNTER2_CSS_PROPERTY_MarkerMid_DOCUMENT"),
+ page: checkGet("USE_COUNTER2_CSS_PROPERTY_MarkerMid_PAGE"),
+ },
+ };
+ let sentinelChanged =
+ !prev_sentinel ||
+ (prev_sentinel.doc != gatheredHistograms.sentinel.doc &&
+ prev_sentinel.page != gatheredHistograms.sentinel.page);
+ return sentinelChanged;
+ },
+ "grabHistogramsFromContent",
+ 100,
+ Infinity
+ ).then(
+ () => gatheredHistograms,
+ function (msg) {
+ throw msg;
+ }
+ );
+}
diff --git a/dom/base/test/browser_user_input_handling_delay.js b/dom/base/test/browser_user_input_handling_delay.js
new file mode 100644
index 0000000000..ccd3369c34
--- /dev/null
+++ b/dom/base/test/browser_user_input_handling_delay.js
@@ -0,0 +1,82 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+async function test_user_input_handling_delay_helper(prefs) {
+ await SpecialPowers.pushPrefEnv({
+ set: prefs,
+ });
+
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ `data:text/html,<body></body>`
+ );
+
+ let canHandleInput = false;
+ let mouseDownPromise = BrowserTestUtils.waitForContentEvent(
+ tab.linkedBrowser,
+ "mousedown"
+ ).then(function () {
+ Assert.ok(
+ canHandleInput,
+ "This promise should be resolved after the 5 seconds mark has passed"
+ );
+ });
+
+ for (let i = 0; i < 10; ++i) {
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 10,
+ 10,
+ { type: "mousedown" },
+ tab.linkedBrowser
+ );
+ }
+ // Wait for roughly 5 seconds to give chances for the
+ // above mousedown event to be handled.
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
+ for (let i = 0; i < 330; ++i) {
+ await new Promise(r => {
+ content.requestAnimationFrame(r);
+ });
+ }
+ });
+
+ // If any user input events were handled in the above 5 seconds
+ // the mouseDownPromise would be resolved with canHandleInput = false,
+ // so that the test would fail.
+ canHandleInput = true;
+
+ // Ensure the events can be handled eventually
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 10,
+ 10,
+ { type: "mousedown" },
+ tab.linkedBrowser
+ );
+
+ await mouseDownPromise;
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test_MinRAF() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 100],
+ ["dom.input_events.security.minTimeElapsedInMS", 0],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_helper(prefs);
+});
+
+add_task(async function test_MinElapsedTime() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 0],
+ ["dom.input_events.security.minTimeElapsedInMS", 5000],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_helper(prefs);
+});
diff --git a/dom/base/test/browser_user_input_handling_delay_aboutblank.js b/dom/base/test/browser_user_input_handling_delay_aboutblank.js
new file mode 100644
index 0000000000..c49a9bf7ed
--- /dev/null
+++ b/dom/base/test/browser_user_input_handling_delay_aboutblank.js
@@ -0,0 +1,58 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+async function test_user_input_handling_delay_aboutblank_helper(prefs) {
+ await SpecialPowers.pushPrefEnv({
+ set: prefs,
+ });
+
+ let newTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, "about:blank");
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
+ // Open about:blank
+ content.window.open();
+ });
+
+ const tab = await newTabOpened;
+
+ let mouseDownPromise = BrowserTestUtils.waitForContentEvent(
+ tab.linkedBrowser,
+ "mousedown"
+ ).then(function () {
+ Assert.ok(true, "about:blank can handle user input events anytime");
+ });
+
+ // Now gBrowser.selectedBrowser is the newly opened about:blank
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 10,
+ 10,
+ { type: "mousedown" },
+ tab.linkedBrowser
+ );
+
+ await mouseDownPromise;
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test_MinRAF_aboutblank() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 100],
+ ["dom.input_events.security.minTimeElapsedInMS", 0],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_aboutblank_helper(prefs);
+});
+
+add_task(async function test_MinElapsedTime_aboutblank() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 0],
+ ["dom.input_events.security.minTimeElapsedInMS", 5000],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_aboutblank_helper(prefs);
+});
diff --git a/dom/base/test/browser_user_input_handling_delay_bfcache.js b/dom/base/test/browser_user_input_handling_delay_bfcache.js
new file mode 100644
index 0000000000..826f4340c5
--- /dev/null
+++ b/dom/base/test/browser_user_input_handling_delay_bfcache.js
@@ -0,0 +1,107 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+async function test_user_input_handling_delay_BFCache_helper(prefs) {
+ await SpecialPowers.pushPrefEnv({
+ set: prefs,
+ });
+
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ `data:text/html,<body></body>`,
+ true
+ );
+
+ let switchAwayPromise = BrowserTestUtils.browserLoaded(
+ browser,
+ false,
+ "about:blank"
+ );
+ // Navigate away to make the page enters BFCache
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.location = "about:blank";
+ });
+ await switchAwayPromise;
+
+ // Navigate back to restore the page from BFCache
+ let pageShownPromise = BrowserTestUtils.waitForContentEvent(
+ tab.linkedBrowser,
+ "pageshow",
+ true
+ );
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.history.back();
+ });
+
+ await pageShownPromise;
+
+ let canHandleInput = false;
+ let mouseDownPromise = BrowserTestUtils.waitForContentEvent(
+ tab.linkedBrowser,
+ "mousedown"
+ ).then(function () {
+ Assert.ok(
+ canHandleInput,
+ "This promise should be resolved after the 5 seconds mark has passed"
+ );
+ });
+ // Ensure the events are discarded initially
+ for (let i = 0; i < 10; ++i) {
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 10,
+ 10,
+ { type: "mousedown" },
+ tab.linkedBrowser
+ );
+ }
+
+ // Wait for roughly 5 seconds to give chances for the
+ // above mousedown event to be handled.
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
+ for (let i = 0; i < 330; ++i) {
+ await new Promise(r => {
+ content.requestAnimationFrame(r);
+ });
+ }
+ });
+
+ // If any user input events were handled in the above 5 seconds
+ // the mouseDownPromise would be resolved with canHandleInput = false,
+ // so that the test would fail.
+ canHandleInput = true;
+
+ // Ensure the events can be handled eventually
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 10,
+ 10,
+ { type: "mousedown" },
+ tab.linkedBrowser
+ );
+
+ await mouseDownPromise;
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test_MinRAF_BFCache() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 100],
+ ["dom.input_events.security.minTimeElapsedInMS", 0],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_BFCache_helper(prefs);
+});
+
+add_task(async function test_MinElapsedTime_BFCache() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 0],
+ ["dom.input_events.security.minTimeElapsedInMS", 5000],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_BFCache_helper(prefs);
+});
diff --git a/dom/base/test/browser_user_input_handling_delay_invisible_iframe.js b/dom/base/test/browser_user_input_handling_delay_invisible_iframe.js
new file mode 100644
index 0000000000..8227a09a08
--- /dev/null
+++ b/dom/base/test/browser_user_input_handling_delay_invisible_iframe.js
@@ -0,0 +1,78 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+async function test_user_input_handling_delay_helper(prefs) {
+ await SpecialPowers.pushPrefEnv({
+ set: prefs,
+ });
+
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ `
+ data:text/html,
+ <body>
+ <iframe width="1" height="1" style="position:absolute; top:-9999px; left: -9999px; border-style: none" src="https://example.org/dom/base/test/empty.html"></iframe>
+ <input />
+ </body>`
+ );
+
+ await BrowserTestUtils.reloadTab(tab);
+
+ let iframeFocused = SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ async function () {
+ let iframe = content.document.querySelector("iframe");
+ await ContentTaskUtils.waitForCondition(function () {
+ return content.document.activeElement == iframe;
+ });
+ }
+ );
+
+ // Now the focus moves to the cross origin iframe
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ content.document.querySelector("iframe").focus();
+ });
+
+ await iframeFocused;
+
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 1000));
+
+ const inputGetFocused = SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ async function () {
+ await ContentTaskUtils.waitForEvent(
+ content.document.querySelector("input"),
+ "focus"
+ );
+ }
+ ).then(function () {
+ Assert.ok(
+ true,
+ "Invisible OOP iframe shouldn't prevent user input event handling"
+ );
+ });
+
+ let iframeBC = tab.linkedBrowser.browsingContext.children[0];
+ // Next tab key should move the focus from the iframe to link
+ await BrowserTestUtils.synthesizeKey("KEY_Tab", {}, iframeBC);
+
+ await inputGetFocused;
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test_InvisibleIframe() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 3],
+ ["dom.input_events.security.minTimeElapsedInMS", 0],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_helper(prefs);
+});
diff --git a/dom/base/test/browser_user_input_handling_delay_reload_ticks.js b/dom/base/test/browser_user_input_handling_delay_reload_ticks.js
new file mode 100644
index 0000000000..8afc7f16bb
--- /dev/null
+++ b/dom/base/test/browser_user_input_handling_delay_reload_ticks.js
@@ -0,0 +1,54 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+async function test_user_input_handling_delay_helper(prefs) {
+ await SpecialPowers.pushPrefEnv({
+ set: prefs,
+ });
+
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ `data:text/html,<body></body>`
+ );
+
+ await BrowserTestUtils.reloadTab(tab);
+
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(r => setTimeout(r, 5000));
+
+ const userInputHappend = SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ async function () {
+ await ContentTaskUtils.waitForEvent(content, "keydown");
+ }
+ ).then(function () {
+ Assert.ok(
+ true,
+ "User input event should be able to work after 5 seconds of an reload"
+ );
+ });
+
+ // In the buggy build, the following tab key doesn't work
+ await BrowserTestUtils.synthesizeKey("KEY_Tab", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("KEY_Tab", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("KEY_Tab", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeKey("KEY_Tab", {}, tab.linkedBrowser);
+
+ await userInputHappend;
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+add_task(async function test_MinTick() {
+ const prefs = [
+ ["dom.input_events.security.minNumTicks", 10],
+ ["dom.input_events.security.minTimeElapsedInMS", 0],
+ ["dom.input_events.security.isUserInputHandlingDelayTest", true],
+ ];
+
+ await test_user_input_handling_delay_helper(prefs);
+});
diff --git a/dom/base/test/browser_xml_toggle.js b/dom/base/test/browser_xml_toggle.js
new file mode 100644
index 0000000000..477db038b1
--- /dev/null
+++ b/dom/base/test/browser_xml_toggle.js
@@ -0,0 +1,24 @@
+const URL = `data:text/xml,
+<?xml version="1.0" encoding="UTF-8"?>
+<note>
+ <to>Tove</to>
+ <from>Jani</from>
+ <heading>Reminder</heading>
+ <body>Don't forget me this weekend!</body>
+</note>
+`;
+
+add_task(async function xml_pretty_print_toggle() {
+ await BrowserTestUtils.withNewTab(URL, async function (browser) {
+ await SpecialPowers.spawn(browser, [], () => {
+ let summary =
+ content.document.documentElement.openOrClosedShadowRoot.querySelector(
+ "summary"
+ );
+ let details = summary.parentNode;
+ ok(details.open, "Should be open");
+ summary.click();
+ ok(!details.open, "Should be closed");
+ });
+ });
+});
diff --git a/dom/base/test/bug1576154.sjs b/dom/base/test/bug1576154.sjs
new file mode 100644
index 0000000000..d18151a8b4
--- /dev/null
+++ b/dom/base/test/bug1576154.sjs
@@ -0,0 +1,8 @@
+function handleRequest(request, response) {
+ response.setStatusLine("1.1", 500, "Internal Server Error");
+ response.setHeader("Content-Type", "image/svg+xml", false);
+
+ let body =
+ "<svg xmlns='http://www.w3.org/2000/svg' width='70' height='0'></svg>";
+ response.bodyOutputStream.write(body, body.length);
+}
diff --git a/dom/base/test/bug1739957.sjs b/dom/base/test/bug1739957.sjs
new file mode 100644
index 0000000000..38f5e72040
--- /dev/null
+++ b/dom/base/test/bug1739957.sjs
@@ -0,0 +1,10 @@
+function handleRequest(request, response) {
+ if (request.queryString == "loaded") {
+ response.write(getState("loaded") || "false");
+ return;
+ }
+
+ setState("loaded", "true");
+ response.setHeader("Content-Type", "image/svg+xml", false);
+ response.write(`<svg xmlns="http://www.w3.org/2000/svg"></svg>`);
+}
diff --git a/dom/base/test/bug282547.sjs b/dom/base/test/bug282547.sjs
new file mode 100644
index 0000000000..a57a176038
--- /dev/null
+++ b/dom/base/test/bug282547.sjs
@@ -0,0 +1,8 @@
+function handleRequest(request, response) {
+ response.setStatusLine(null, 401, "Unauthorized");
+
+ response.setHeader("WWW-Authenticate", 'basic realm="restricted"', false);
+
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+ response.setHeader("Access-Control-Allow-Credentials", "true", false);
+}
diff --git a/dom/base/test/bug298064-subframe.html b/dom/base/test/bug298064-subframe.html
new file mode 100644
index 0000000000..af497f5905
--- /dev/null
+++ b/dom/base/test/bug298064-subframe.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <script>
+ function test_func() {
+ var bar = new Option();
+ parent.is(bar.ownerDocument, document,
+ "Unexpected document for our new option");
+ bar = new Image();
+ parent.is(bar.ownerDocument, document,
+ "Unexpected document for our new image");
+ bar = new parent.Option();
+ parent.is(bar.ownerDocument, parent.document,
+ "Unexpected document for parent new option");
+ bar = new parent.Image();
+ parent.is(bar.ownerDocument, parent.document,
+ "Unexpected document for parent new image");
+ parent.isnot(parent.document, document, "Documents should be different");
+ }
+ </script>
+ </head>
+<html>
+
+
diff --git a/dom/base/test/bug313646.txt b/dom/base/test/bug313646.txt
new file mode 100644
index 0000000000..150f5ea6d1
--- /dev/null
+++ b/dom/base/test/bug313646.txt
@@ -0,0 +1 @@
+Nothing to see here. Just need to request this file via XHR.
diff --git a/dom/base/test/bug382113_object.html b/dom/base/test/bug382113_object.html
new file mode 100644
index 0000000000..935f00afd1
--- /dev/null
+++ b/dom/base/test/bug382113_object.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<title></title>
+<body onload="parent.childGotOnload = true;">
+ <p>A Document in an &lt;object&gt;</p>
+</body>
+
diff --git a/dom/base/test/bug403852_fileOpener.js b/dom/base/test/bug403852_fileOpener.js
new file mode 100644
index 0000000000..b35fa8fbcf
--- /dev/null
+++ b/dom/base/test/bug403852_fileOpener.js
@@ -0,0 +1,24 @@
+/* eslint-env mozilla/chrome-script */
+
+Cu.importGlobalProperties(["File"]);
+
+var testFile = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIDirectoryService)
+ .QueryInterface(Ci.nsIProperties)
+ .get("ProfD", Ci.nsIFile);
+testFile.append("prefs.js");
+
+addMessageListener("file.open", function () {
+ File.createFromNsIFile(testFile).then(function (file) {
+ File.createFromNsIFile(testFile, { lastModified: 123 }).then(function (
+ fileWithDate
+ ) {
+ sendAsyncMessage("file.opened", {
+ file,
+ mtime: testFile.lastModifiedTime,
+ fileWithDate,
+ fileDate: 123,
+ });
+ });
+ });
+});
diff --git a/dom/base/test/bug419132.html b/dom/base/test/bug419132.html
new file mode 100644
index 0000000000..ab2934c2d4
--- /dev/null
+++ b/dom/base/test/bug419132.html
@@ -0,0 +1,22 @@
+<html><head>
+</head><body>
+<span>
+<span id="a" tabindex="1">
+<span>
+
+<select>
+<script>
+document.getElementById('a').focus();
+</script>
+</select>
+
+<style>
+#a:focus { float:right;}
+body *:first-child {-moz-binding:url(data:text/xml;charset=utf-8,%3Cbindings%20xmlns%3D%22http%3A//www.mozilla.org/xbl%22%3E%0A%3Cbinding%20id%3D%22a%22%20inheritstyle%3D%22false%22%3E%0A%3Ccontent%3E%0A%3Cchildren/%3E%0A%3Cinput%20xmlns%3D%22http%3A//www.w3.org/1999/xhtml%22%20style%3D%22display%3A%20table%3B%20overflow%3A%20hidden%3B%22%20/%3E%0A%3C/content%3E%0A%3C/binding%3E%0A%3C/bindings%3E);
+</style>
+
+</span>
+</span>
+</span>
+</body>
+</html>
diff --git a/dom/base/test/bug426308-redirect.sjs b/dom/base/test/bug426308-redirect.sjs
new file mode 100644
index 0000000000..331f31d96a
--- /dev/null
+++ b/dom/base/test/bug426308-redirect.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+ response.setStatusLine(null, 302, "Found");
+ response.setHeader("Location", request.queryString, false);
+}
diff --git a/dom/base/test/bug435425.sjs b/dom/base/test/bug435425.sjs
new file mode 100644
index 0000000000..0e3ef38419
--- /dev/null
+++ b/dom/base/test/bug435425.sjs
@@ -0,0 +1,25 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/plain", false);
+ if (request.method == "GET") {
+ response.write(request.queryString);
+ } else {
+ var body = new BinaryInputStream(request.bodyInputStream);
+
+ var avail;
+ var bytes = [];
+
+ while ((avail = body.available()) > 0) {
+ Array.prototype.push.apply(bytes, body.readByteArray(avail));
+ }
+
+ var data = String.fromCharCode.apply(null, bytes);
+ response.bodyOutputStream.write(data, data.length);
+ }
+}
diff --git a/dom/base/test/bug435425_redirect.sjs b/dom/base/test/bug435425_redirect.sjs
new file mode 100644
index 0000000000..14fec62331
--- /dev/null
+++ b/dom/base/test/bug435425_redirect.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+ response.setStatusLine(null, 302, "Moved");
+ response.setHeader("Location", "http://nosuchdomain.localhost", false);
+}
diff --git a/dom/base/test/bug444322.js b/dom/base/test/bug444322.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/base/test/bug444322.js
diff --git a/dom/base/test/bug444322.txt b/dom/base/test/bug444322.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/base/test/bug444322.txt
diff --git a/dom/base/test/bug444546.sjs b/dom/base/test/bug444546.sjs
new file mode 100644
index 0000000000..5861eeb25c
--- /dev/null
+++ b/dom/base/test/bug444546.sjs
@@ -0,0 +1,21 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/plain", false);
+
+ var body = new BinaryInputStream(request.bodyInputStream);
+
+ var avail;
+ var bytes = [];
+ while ((avail = body.available()) > 0) {
+ Array.prototype.push.apply(bytes, body.readByteArray(avail));
+ }
+
+ var data = String.fromCharCode.apply(null, bytes);
+ response.bodyOutputStream.write(data, data.length);
+}
diff --git a/dom/base/test/bug455629-helper.svg b/dom/base/test/bug455629-helper.svg
new file mode 100644
index 0000000000..38098585ed
--- /dev/null
+++ b/dom/base/test/bug455629-helper.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg">
+ <g transform="scale(0.5)">
+ <foreignObject id="f" width="100" height="100"/>
+ </g>
+</svg>
diff --git a/dom/base/test/bug457746.sjs b/dom/base/test/bug457746.sjs
new file mode 100644
index 0000000000..caa4433cde
--- /dev/null
+++ b/dom/base/test/bug457746.sjs
@@ -0,0 +1,10 @@
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/plain; charset=ISO-8859-1", false);
+ const body = [0xc1];
+ var bos = Components.classes[
+ "@mozilla.org/binaryoutputstream;1"
+ ].createInstance(Components.interfaces.nsIBinaryOutputStream);
+ bos.setOutputStream(response.bodyOutputStream);
+
+ bos.writeByteArray(body);
+}
diff --git a/dom/base/test/bug461735-post-redirect.js b/dom/base/test/bug461735-post-redirect.js
new file mode 100644
index 0000000000..950948e4c9
--- /dev/null
+++ b/dom/base/test/bug461735-post-redirect.js
@@ -0,0 +1,3 @@
+var a = 0;
+var b = 0;
+c();
diff --git a/dom/base/test/bug461735-redirect1.sjs b/dom/base/test/bug461735-redirect1.sjs
new file mode 100644
index 0000000000..cf00e8b8c4
--- /dev/null
+++ b/dom/base/test/bug461735-redirect1.sjs
@@ -0,0 +1,8 @@
+function handleRequest(request, response) {
+ response.setStatusLine(null, 302, "Found");
+ response.setHeader(
+ "Location",
+ "http://example.com/tests/dom/base/test/bug461735-post-redirect.js",
+ false
+ );
+}
diff --git a/dom/base/test/bug461735-redirect2.sjs b/dom/base/test/bug461735-redirect2.sjs
new file mode 100644
index 0000000000..416882003c
--- /dev/null
+++ b/dom/base/test/bug461735-redirect2.sjs
@@ -0,0 +1,8 @@
+function handleRequest(request, response) {
+ response.setStatusLine(null, 302, "Found");
+ response.setHeader(
+ "Location",
+ "http://mochi.test:8888/tests/dom/base/test/bug461735-post-redirect.js",
+ false
+ );
+}
diff --git a/dom/base/test/bug466080.sjs b/dom/base/test/bug466080.sjs
new file mode 100644
index 0000000000..df3687000b
--- /dev/null
+++ b/dom/base/test/bug466080.sjs
@@ -0,0 +1,14 @@
+function handleRequest(request, response) {
+ var body = "loaded";
+ var origin = "localhost";
+ try {
+ var origin = request.getHeader("Origin");
+ } catch (e) {}
+
+ response.setHeader("Access-Control-Allow-Origin", origin, false);
+ response.setHeader("Access-Control-Allow-Credentials", "true", false);
+ response.setHeader("Access-Control-Allow-Methods", "XMETHOD", false);
+ response.setHeader("Connection", "Keep-alive", false);
+
+ response.bodyOutputStream.write(body, body.length);
+}
diff --git a/dom/base/test/bug466409-empty.css b/dom/base/test/bug466409-empty.css
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/base/test/bug466409-empty.css
diff --git a/dom/base/test/bug466409-page.html b/dom/base/test/bug466409-page.html
new file mode 100644
index 0000000000..69ce7c2272
--- /dev/null
+++ b/dom/base/test/bug466409-page.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <link rel="stylesheet" type="text/css" href="bug466409-empty.css">
+ <title>Bug</title>
+ <SCRIPT LANGUAGE="JavaScript">
+ document.write("Hello, world!");
+ </SCRIPT>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/base/test/bug475156.sjs b/dom/base/test/bug475156.sjs
new file mode 100644
index 0000000000..9c54b69f65
--- /dev/null
+++ b/dom/base/test/bug475156.sjs
@@ -0,0 +1,23 @@
+function handleRequest(request, response) {
+ if (request.queryString == "") {
+ var etag = request.hasHeader("If-Match")
+ ? request.getHeader("If-Match")
+ : null;
+ if (!etag || etag == getState("etag")) {
+ response.setStatusLine(request.httpVersion, 200, "Ok");
+ response.setHeader("Content-Type", "text/html");
+ response.setHeader("ETag", getState("etag"));
+ response.setHeader("Cache-control", "max-age=36000");
+ response.write(getState("etag"));
+ } else if (etag) {
+ response.setStatusLine(request.httpVersion, 412, "Precondition Failed");
+ }
+ } else {
+ var etag = request.queryString.match(/^etag=(.*)$/);
+ if (etag) {
+ setState("etag", etag[1]);
+ }
+
+ response.setStatusLine(request.httpVersion, 204, "No content");
+ }
+}
diff --git a/dom/base/test/bug482935.sjs b/dom/base/test/bug482935.sjs
new file mode 100644
index 0000000000..b480c40e41
--- /dev/null
+++ b/dom/base/test/bug482935.sjs
@@ -0,0 +1,12 @@
+function handleRequest(request, response) {
+ var body = "initial";
+
+ try {
+ body = request.getHeader("X-Request");
+ } catch (e) {
+ body = "request.getHeader() failed! Exception: " + e;
+ }
+
+ response.setHeader("Cache-Control", "max-age=3600");
+ response.bodyOutputStream.write(body, body.length);
+}
diff --git a/dom/base/test/bug540854.sjs b/dom/base/test/bug540854.sjs
new file mode 100644
index 0000000000..5861eeb25c
--- /dev/null
+++ b/dom/base/test/bug540854.sjs
@@ -0,0 +1,21 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/plain", false);
+
+ var body = new BinaryInputStream(request.bodyInputStream);
+
+ var avail;
+ var bytes = [];
+ while ((avail = body.available()) > 0) {
+ Array.prototype.push.apply(bytes, body.readByteArray(avail));
+ }
+
+ var data = String.fromCharCode.apply(null, bytes);
+ response.bodyOutputStream.write(data, data.length);
+}
diff --git a/dom/base/test/bug578096LoadChromeScript.js b/dom/base/test/bug578096LoadChromeScript.js
new file mode 100644
index 0000000000..443fc34253
--- /dev/null
+++ b/dom/base/test/bug578096LoadChromeScript.js
@@ -0,0 +1,20 @@
+/* eslint-env mozilla/chrome-script */
+
+var file;
+Cu.importGlobalProperties(["File"]);
+
+addMessageListener("file.create", function (message) {
+ file = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties)
+ .get("TmpD", Ci.nsIFile);
+ file.append("foo.txt");
+ file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
+ File.createFromNsIFile(file).then(function (domFile) {
+ sendAsyncMessage("file.created", domFile);
+ });
+});
+
+addMessageListener("file.remove", function (message) {
+ file.remove(false);
+ sendAsyncMessage("file.removed", {});
+});
diff --git a/dom/base/test/bug638112-response.txt b/dom/base/test/bug638112-response.txt
new file mode 100644
index 0000000000..9ce788da79
--- /dev/null
+++ b/dom/base/test/bug638112-response.txt
Binary files differ
diff --git a/dom/base/test/bug638112.sjs b/dom/base/test/bug638112.sjs
new file mode 100644
index 0000000000..3fb6fb90f0
--- /dev/null
+++ b/dom/base/test/bug638112.sjs
@@ -0,0 +1,24 @@
+function getInputStream(path) {
+ var file = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+ var fis = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+ var split = path.split("/");
+ for (var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+ fis.init(file, -1, -1, false);
+ return fis;
+}
+
+function handleRequest(request, response) {
+ var inputStream = getInputStream(
+ "tests/dom/base/test/bug638112-response.txt"
+ );
+ response.seizePower();
+ response.bodyOutputStream.writeFrom(inputStream, inputStream.available());
+ response.finish();
+ inputStream.close();
+}
diff --git a/dom/base/test/bug696301-script-1.js b/dom/base/test/bug696301-script-1.js
new file mode 100644
index 0000000000..98577364df
--- /dev/null
+++ b/dom/base/test/bug696301-script-1.js
@@ -0,0 +1,3 @@
+var a = 0;
+var global = "ran";
+c();
diff --git a/dom/base/test/bug696301-script-1.js^headers^ b/dom/base/test/bug696301-script-1.js^headers^
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/dom/base/test/bug696301-script-1.js^headers^
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/dom/base/test/bug696301-script-2.js b/dom/base/test/bug696301-script-2.js
new file mode 100644
index 0000000000..98577364df
--- /dev/null
+++ b/dom/base/test/bug696301-script-2.js
@@ -0,0 +1,3 @@
+var a = 0;
+var global = "ran";
+c();
diff --git a/dom/base/test/bug704320.sjs b/dom/base/test/bug704320.sjs
new file mode 100644
index 0000000000..f63b5d3a7e
--- /dev/null
+++ b/dom/base/test/bug704320.sjs
@@ -0,0 +1,396 @@
+var BASE_URL = "example.com/tests/dom/base/test/bug704320.sjs";
+
+function createTestUrl(schemeFrom, schemeTo, policy, action, type) {
+ return (
+ schemeTo +
+ "://" +
+ BASE_URL +
+ "?" +
+ "action=" +
+ action +
+ "&" +
+ "scheme=" +
+ schemeFrom +
+ "-to-" +
+ schemeTo +
+ "&" +
+ "policy=" +
+ policy +
+ "&" +
+ "type=" +
+ type
+ );
+}
+
+function create2ndLevelIframeUrl(schemeFrom, schemeTo, policy, type) {
+ return (
+ schemeFrom +
+ "://" +
+ BASE_URL +
+ "?" +
+ "action=create-2nd-level-iframe&" +
+ "scheme-from=" +
+ schemeFrom +
+ "&" +
+ "scheme-to=" +
+ schemeTo +
+ "&" +
+ "policy=" +
+ policy +
+ "&" +
+ "type=" +
+ type
+ );
+}
+
+// Creates the following test cases for the specified scheme and referrer
+// policy combination:
+// <link>
+// @import
+// font-face
+// bg-url
+// <script>
+// <img>
+// <iframe>
+// <audio>
+// <video>
+// <object type="bogus">
+// <object type="image/svg+xml">
+// <a>
+// <a ping>
+// <form>
+// window.location
+// window.open
+// XMLHttpRequest
+// EventSource
+// TODO: XSLT?
+//
+// This returns a page that loads all of the above resources and contains a
+// script that clicks a link after all resources are (hopefully)
+// loaded. The click triggers a redirection to file_bug704320_redirect.html,
+// which in turn notifies the main window that it's time to check the test
+// results.
+function createTest(schemeFrom, schemeTo, policy, optionalEarlierPolicy) {
+ var _createTestUrl = createTestUrl.bind(
+ null,
+ schemeFrom,
+ schemeTo,
+ policy,
+ "test"
+ );
+
+ var _create2ndLevelIframeUrl = create2ndLevelIframeUrl.bind(
+ null,
+ schemeFrom,
+ schemeTo,
+ policy
+ );
+
+ var metaReferrerPolicyString = "";
+ if (optionalEarlierPolicy && optionalEarlierPolicy != "") {
+ metaReferrerPolicyString +=
+ '<meta name="referrer" content="' + optionalEarlierPolicy + '">\n';
+ }
+ metaReferrerPolicyString += '<meta name="referrer" content="' + policy + '">';
+
+ return (
+ "<!DOCTYPE HTML>\n\
+ <html>\n\
+ <head>\n\
+ " +
+ metaReferrerPolicyString +
+ '\n\
+ <link rel="stylesheet" type="text/css" href="' +
+ _createTestUrl("stylesheet") +
+ '">\n\
+ <style type="text/css">\n\
+ @import "' +
+ _createTestUrl("import-css") +
+ '";\n\
+ @font-face {\n\
+ font-family: "Fake Serif Bold";\n\
+ src: url("' +
+ _createTestUrl("font-face") +
+ '");\n\
+ }\n\
+ body {\n\
+ font-family: "Fake Serif Bold", serif;\n\
+ background: url("' +
+ _createTestUrl("bg-url") +
+ '");\n\
+ }\n\
+ </style>\n\
+ </head>\n\
+ <body>\n\
+ <script src="' +
+ _createTestUrl("script") +
+ '"></script>\n\
+ <img src="' +
+ _createTestUrl("img") +
+ '"></img>\n\
+ <iframe src="' +
+ _createTestUrl("iframe") +
+ '"></iframe>\n\
+ <audio src="' +
+ _createTestUrl("audio") +
+ '"></audio>\n\
+ <video src="' +
+ _createTestUrl("video") +
+ '"></video>\n\
+ <object type="bogus" data="' +
+ _createTestUrl("object") +
+ '"></object>\n\
+ <object type="image/svg+xml" data="' +
+ _createTestUrl("object-svg") +
+ '"></object>\n\
+ <a id="link" href="' +
+ _createTestUrl("link") +
+ '" ping="' +
+ _createTestUrl("link-ping") +
+ '"></a>\n\
+ <iframe src="' +
+ _create2ndLevelIframeUrl("form") +
+ '"></iframe>\n\
+ <iframe src="' +
+ _create2ndLevelIframeUrl("window.location") +
+ '"></iframe>\n\
+ <script>\n\
+ var _testFinished = 0\n\
+ (function() {\n\
+ var x = new XMLHttpRequest();\n\
+ x.open("GET", "' +
+ _createTestUrl("xmlhttprequest") +
+ '");\n\
+ x.send();\n\
+ })();\n\
+ (function() {\n\
+ var eventSource = new EventSource("' +
+ _createTestUrl("eventsource") +
+ '");\n\
+ })();' +
+ // LOAD EVENT (most of the tests)
+ // fires when the resources for the page are loaded
+ 'var _isLoaded = false;\n\
+ window.addEventListener("load", function() {\n\
+ this._isLoaded = true;\n\
+ this.checkForFinish();\n\
+ }.bind(window), false);' +
+ // WINDOW.OPEN test
+ // listen for incoming status from window.open, close the window
+ // and check if we're done.
+ 'var _openedWindowLoaded = false;\n\
+ window.addEventListener("message", function(message) {\n\
+ if (message.data == "window.open") {\n\
+ this._openedWindowLoaded = true;\n\
+ this.win.close();\n\
+ this.checkForFinish();\n\
+ }\n\
+ }.bind(window), false);\n\
+ var win = window.open("' +
+ _createTestUrl("window.open") +
+ '", "");' +
+ // called by the two things that must complete: window.open page
+ // and the window load event. When both are complete, this
+ // "finishes" the iframe subtest by clicking the link.
+ // _testFinished avoids calling this function twice (which may happen)
+ 'function checkForFinish() {\n\
+ if (window._isLoaded && window._openedWindowLoaded && !window._testFinished) {\n\
+ window._testFinished = 1;\n\
+ document.getElementById("link").click();\n\
+ }\n\
+ }\n\
+ </script>\n\
+ </body>\n\
+ </html>'
+ );
+}
+
+function createIframedFormTest(schemeFrom, schemeTo, policy) {
+ var actionUrl = schemeTo + "://" + BASE_URL;
+
+ return (
+ '<!DOCTYPE HTML>\n\
+ <html>\n\
+ <head>\n\
+ <meta name="referrer" content="' +
+ policy +
+ '">\n\
+ </head>\n\
+ <body>\n\
+ <form id="form" action="' +
+ actionUrl +
+ '">\n\
+ <input type="hidden" name="action" value="test">\n\
+ <input type="hidden" name="scheme" value="' +
+ schemeFrom +
+ "-to-" +
+ schemeTo +
+ '">\n\
+ <input type="hidden" name="policy" value="' +
+ policy +
+ '">\n\
+ <input type="hidden" name="type" value="form">\n\
+ </form>\n\
+ <script>\n\
+ document.getElementById("form").submit();\n\
+ </script>\n\
+ </body>\n\
+ </html>'
+ );
+}
+
+function createIframedWindowLocationTest(schemeFrom, schemeTo, policy) {
+ var url = createTestUrl(
+ schemeFrom,
+ schemeTo,
+ policy,
+ "test",
+ "window.location"
+ );
+
+ return (
+ '<!DOCTYPE HTML>\n\
+ <html>\n\
+ <head>\n\
+ <meta name="referrer" content="' +
+ policy +
+ '">\n\
+ </head>\n\
+ <body>\n\
+ <script>\n\
+ window.location = "' +
+ url +
+ '";\n\
+ </script>\n\
+ </body>\n\
+ </html>'
+ );
+}
+
+function createPolicyTest(policy, optionalEarlierPolicy) {
+ var metaReferrerPolicyString = "";
+ if (optionalEarlierPolicy && optionalEarlierPolicy != "") {
+ metaReferrerPolicyString +=
+ '<meta name="referrer" content="' + optionalEarlierPolicy + '">\n';
+ }
+ metaReferrerPolicyString += '<meta name="referrer" content="' + policy + '">';
+
+ return (
+ "<!DOCTYPE HTML>\n\
+ <html>\n\
+ <head>\n\
+ " +
+ metaReferrerPolicyString +
+ '\n\
+ <script type="text/javascript" src="/tests/dom/base/test/file_bug704320_preload_common.js"></script>\n\
+ </head>\n\
+ <body>\n\
+ <img src="/tests/dom/base/test/bug704320_counter.sjs?type=img"\n\
+ onload="incrementLoad2(\'img\', 2);">\n\
+ <img src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=img"\n\
+ onload="incrementLoad2(\'img\', 2);">\n\
+ </body>\n\
+ </html>'
+ );
+}
+
+function handleRequest(request, response) {
+ var sharedKey = "bug704320.sjs";
+ var params = request.queryString.split("&");
+ var action = params[0].split("=")[1];
+
+ if (action === "create-1st-level-iframe") {
+ // ?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin
+ var schemeFrom = params[1].split("=")[1];
+ var schemeTo = params[2].split("=")[1];
+ var policy = params[3].split("=")[1];
+ var optionalEarlierPolicy = "";
+ if (params[4]) {
+ optionalEarlierPolicy = params[4].split("=")[1];
+ }
+
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.write(
+ createTest(schemeFrom, schemeTo, policy, optionalEarlierPolicy)
+ );
+ } else if (action === "create-2nd-level-iframe") {
+ // ?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=origin&type=form"
+ var schemeFrom = params[1].split("=")[1];
+ var schemeTo = params[2].split("=")[1];
+ var policy = params[3].split("=")[1];
+ var type = params[4].split("=")[1];
+
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (type === "form") {
+ response.write(createIframedFormTest(schemeFrom, schemeTo, policy));
+ } else if (type === "window.location") {
+ response.write(
+ createIframedWindowLocationTest(schemeFrom, schemeTo, policy)
+ );
+ }
+ } else if (action === "test") {
+ // ?action=test&scheme=http-to-https&policy=origin&type=img
+ var scheme = params[1].split("=")[1];
+ var policy = params[2].split("=")[1];
+ var type = params[3].split("=")[1];
+ var result = getSharedState(sharedKey);
+
+ if (result === "") {
+ result = {};
+ } else {
+ result = JSON.parse(result);
+ }
+
+ if (!result[type]) {
+ result[type] = {};
+ }
+
+ if (!result[type][scheme]) {
+ result[type][scheme] = {};
+ }
+
+ if (request.hasHeader("Referer")) {
+ result[type][scheme][policy] = request.getHeader("Referer");
+ } else {
+ result[type][scheme][policy] = "";
+ }
+
+ setSharedState(sharedKey, JSON.stringify(result));
+
+ if (type === "link") {
+ var loc =
+ "https://example.com/tests/dom/base/test/file_bug704320_redirect.html";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+ }
+
+ if (type === "window.open") {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(
+ "<html><body><script>" +
+ 'window.opener.postMessage("window.open", "*");' +
+ "</script></body></html>"
+ );
+ }
+ } else if (action === "get-test-results") {
+ // ?action=get-result
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(getSharedState(sharedKey));
+ } else if (action === "generate-policy-test") {
+ // ?action=generate-policy-test&policy=b64-encoded-string
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ var policy = unescape(params[1].split("=")[1]);
+ var optionalEarlierPolicy = "";
+ if (params[2]) {
+ optionalEarlierPolicy = params[2].split("=")[1];
+ }
+
+ response.write(createPolicyTest(policy, optionalEarlierPolicy));
+ }
+}
diff --git a/dom/base/test/bug704320_counter.sjs b/dom/base/test/bug704320_counter.sjs
new file mode 100644
index 0000000000..061bd751d9
--- /dev/null
+++ b/dom/base/test/bug704320_counter.sjs
@@ -0,0 +1,96 @@
+// Handle counting loads for bug 704320.
+
+const SHARED_KEY = "bug704320_counter";
+const DEFAULT_STATE = {
+ css: { count: 0, referrers: [] },
+ img: { count: 0, referrers: [] },
+ js: { count: 0, referrers: [] },
+};
+const TYPE_MAP = {
+ css: "text/css",
+ js: "application/javascript",
+ img: "image/png",
+ html: "text/html",
+};
+
+// Writes an image to the response
+function WriteOutImage(response) {
+ var file = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+
+ file.append("tests");
+ file.append("image");
+ file.append("test");
+ file.append("mochitest");
+ file.append("blue.png");
+
+ var fileStream = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+ fileStream.init(file, 1, 0, false);
+ response.bodyOutputStream.writeFrom(fileStream, fileStream.available());
+}
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ var referrerLevel = "none";
+ if (request.hasHeader("Referer")) {
+ let referrer = request.getHeader("Referer");
+ if (referrer.indexOf("bug704320") > 0) {
+ referrerLevel = "full";
+ } else if (referrer == "http://mochi.test:8888/") {
+ referrerLevel = "origin";
+ }
+ }
+
+ var state = getSharedState(SHARED_KEY);
+ if (state === "") {
+ state = DEFAULT_STATE;
+ } else {
+ state = JSON.parse(state);
+ }
+
+ response.setStatusLine(request.httpVersion, 200, "OK");
+
+ //avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if ("reset" in query) {
+ //reset server state
+ setSharedState(SHARED_KEY, JSON.stringify(DEFAULT_STATE));
+ //serve any CSS that we want to use.
+ response.write("");
+ return;
+ }
+
+ if ("results" in query) {
+ response.setHeader("Content-Type", "text/javascript", false);
+ response.write(JSON.stringify(state));
+ return;
+ }
+
+ if ("type" in query) {
+ state[query.type].count++;
+ response.setHeader("Content-Type", TYPE_MAP[query.type], false);
+ if (state[query.type].referrers.indexOf(referrerLevel) < 0) {
+ state[query.type].referrers.push(referrerLevel);
+ }
+
+ if (query.type == "img") {
+ WriteOutImage(response);
+ }
+ }
+
+ if ("content" in query) {
+ response.write(unescape(query.content));
+ }
+
+ setSharedState(SHARED_KEY, JSON.stringify(state));
+ return;
+}
diff --git a/dom/base/test/bug819051.sjs b/dom/base/test/bug819051.sjs
new file mode 100644
index 0000000000..b880d4efe3
--- /dev/null
+++ b/dom/base/test/bug819051.sjs
@@ -0,0 +1,9 @@
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, 200, "Ok");
+ response.setHeader(
+ "X-appended-result",
+ request.getHeader("X-appended-to-this")
+ );
+ response.setHeader("X-Accept-Result", request.getHeader("Accept"));
+ response.write("");
+}
diff --git a/dom/base/test/chrome.ini b/dom/base/test/chrome.ini
new file mode 100644
index 0000000000..08302adc2a
--- /dev/null
+++ b/dom/base/test/chrome.ini
@@ -0,0 +1,42 @@
+[DEFAULT]
+skip-if = os == 'android'
+support-files =
+ file_empty.html
+ file_blocking_image.html
+ file_bug945152.jar
+ file_bug945152_worker.js
+ file_bug1008126_worker.js
+ file_inline_script.html
+ file_inline_script.xhtml
+ file_external_script.html
+ file_external_script.xhtml
+ file_script.js
+ file_serializer_noscript.html
+ referrer_helper.js
+ referrer_testserver.sjs
+ !/image/test/mochitest/shaver.png
+
+[test_anonymousContent_xul_window.xhtml]
+[test_blockParsing.html]
+[test_blocking_image.html]
+[test_bug419527.xhtml]
+[test_bug564863-2.xhtml]
+[test_bug945152.html]
+[test_bug1008126.html]
+[test_bug1016960.html]
+[test_bug1120222.html]
+[test_anchor_target_blank_referrer.html]
+[test_domrequesthelper.xhtml]
+[test_fragment_sanitization.xhtml]
+[test_getLastOverWindowPointerLocationInCSSPixels.html]
+support-files = !/gfx/layers/apz/test/mochitest/apz_test_utils.js
+[test_messagemanager_send_principal.html]
+[test_navigator_resolve_identity_xrays.xhtml]
+support-files = file_navigator_resolve_identity_xrays.xhtml
+[test_sandboxed_blob_uri.html]
+[test_sendQueryContentAndSelectionSetEvent.html]
+[test_sendSelectionSetEvent_with_same_range.html]
+[test_urgent_start.html]
+skip-if = (os == "win" && debug) || (os == "mac" && debug) #leaks Bug 1571583
+[test_sanitize_xhr.html]
+[test_serializer_noscript.html]
diff --git a/dom/base/test/chrome/bug418986-1.js b/dom/base/test/chrome/bug418986-1.js
new file mode 100644
index 0000000000..7c39df0c13
--- /dev/null
+++ b/dom/base/test/chrome/bug418986-1.js
@@ -0,0 +1,88 @@
+/* globals chromeWindow */
+// The main test function.
+var test = function (isContent) {
+ SimpleTest.waitForExplicitFinish();
+
+ SpecialPowers.pushPrefEnv({
+ set: [["security.allow_eval_with_system_principal", true]],
+ });
+
+ if (!isContent) {
+ let { ww } = SpecialPowers.Services;
+ window.chromeWindow = ww.activeWindow;
+ }
+
+ // The pairs of values expected to be the same when
+ // fingerprinting resistance is enabled.
+ let pairs = [
+ ["screenX", 0],
+ ["screenY", 0],
+ ["mozInnerScreenX", 0],
+ ["mozInnerScreenY", 0],
+ ["screen.pixelDepth", 24],
+ ["screen.colorDepth", 24],
+ ["screen.availWidth", "innerWidth"],
+ ["screen.availHeight", "innerHeight"],
+ ["screen.left", 0],
+ ["screen.top", 0],
+ ["screen.availLeft", 0],
+ ["screen.availTop", 0],
+ ["screen.width", "innerWidth"],
+ ["screen.height", "innerHeight"],
+ ["screen.orientation.type", "'landscape-primary'"],
+ ["screen.orientation.angle", 0],
+ ["screen.mozOrientation", "'landscape-primary'"],
+ ["devicePixelRatio", 1],
+ ];
+
+ // checkPair: tests if members of pair [a, b] are equal when evaluated.
+ let checkPair = function (a, b) {
+ // eslint-disable-next-line no-eval
+ is(eval(a), eval(b), a + " should be equal to " + b);
+ };
+
+ // Returns generator object that iterates through pref values.
+ let prefVals = (function* () {
+ yield false;
+ yield true;
+ })();
+
+ // The main test function, runs until all pref values are exhausted.
+ let nextTest = function () {
+ let { value: prefValue, done } = prefVals.next();
+ if (done) {
+ SimpleTest.finish();
+ return;
+ }
+ SpecialPowers.pushPrefEnv(
+ { set: [["privacy.resistFingerprinting", prefValue]] },
+ function () {
+ // We will be resisting fingerprinting if the pref is enabled,
+ // and we are in a content script (not chrome).
+ let resisting = prefValue && isContent;
+ // Check each of the pairs.
+ pairs.map(function ([item, onVal]) {
+ if (resisting) {
+ checkPair("window." + item, onVal);
+ } else if (!isContent && !item.startsWith("moz")) {
+ checkPair("window." + item, "chromeWindow." + item);
+ }
+ });
+ if (!isContent && !resisting) {
+ // Hard to predict these values, but we can enforce constraints:
+ ok(
+ window.mozInnerScreenX >= chromeWindow.mozInnerScreenX,
+ "mozInnerScreenX"
+ );
+ ok(
+ window.mozInnerScreenY >= chromeWindow.mozInnerScreenY,
+ "mozInnerScreenY"
+ );
+ }
+ nextTest();
+ }
+ );
+ };
+
+ nextTest();
+};
diff --git a/dom/base/test/chrome/bug421622-referer.sjs b/dom/base/test/chrome/bug421622-referer.sjs
new file mode 100644
index 0000000000..14cab00de4
--- /dev/null
+++ b/dom/base/test/chrome/bug421622-referer.sjs
@@ -0,0 +1,9 @@
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/plain", false);
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ var referer = request.hasHeader("Referer")
+ ? request.getHeader("Referer")
+ : "";
+ response.write("Referer: " + referer);
+}
diff --git a/dom/base/test/chrome/bug884693.sjs b/dom/base/test/chrome/bug884693.sjs
new file mode 100644
index 0000000000..f2650753f2
--- /dev/null
+++ b/dom/base/test/chrome/bug884693.sjs
@@ -0,0 +1,8 @@
+function handleRequest(request, response) {
+ let [status, statusText, encodedBody] = request.queryString.split("&");
+ let body = decodeURIComponent(encodedBody);
+ response.setStatusLine(request.httpVersion, status, statusText);
+ response.setHeader("Content-Type", "text/xml", false);
+ response.setHeader("Content-Length", "" + body.length, false);
+ response.write(body);
+}
diff --git a/dom/base/test/chrome/chrome.ini b/dom/base/test/chrome/chrome.ini
new file mode 100644
index 0000000000..5dde748a67
--- /dev/null
+++ b/dom/base/test/chrome/chrome.ini
@@ -0,0 +1,84 @@
+[DEFAULT]
+skip-if = os == 'android'
+support-files =
+ bug418986-1.js
+ clonedoc/**
+ file_bug549682.xhtml
+ file_bug616841.xhtml
+ file_bug816340.xhtml
+ file_bug990812-1.xhtml
+ file_bug990812-2.xhtml
+ file_bug990812-3.xhtml
+ file_bug990812-4.xhtml
+ file_bug990812-5.xhtml
+ file_bug1139964.xhtml
+ file_bug1209621.xhtml
+ fileconstructor_file.png
+ frame_custom_element_content.html
+ custom_element_ep.js
+ window_nsITextInputProcessor.xhtml
+ title_window.xhtml
+ window_swapFrameLoaders.xhtml
+prefs =
+ gfx.font_rendering.fallback.async=false
+
+[test_bug120684.xhtml]
+[test_bug206691.xhtml]
+[test_bug289714.xhtml]
+[test_bug339494.xhtml]
+[test_bug357450.xhtml]
+support-files = ../file_bug357450.js
+[test_bug380418.html]
+[test_bug380418.html^headers^]
+[test_bug383430.html]
+[test_bug418986-1.xhtml]
+[test_bug421622.xhtml]
+[test_bug429785.xhtml]
+[test_bug430050.xhtml]
+[test_bug467123.xhtml]
+[test_bug473284.xhtml]
+[test_bug549682.xhtml]
+skip-if = verify
+[test_bug571390.xhtml]
+[test_bug1098074_throw_from_ReceiveMessage.xhtml]
+[test_bug616841.xhtml]
+[test_bug635835.xhtml]
+[test_bug682305.html]
+[test_bug683852.xhtml]
+[test_bug752226-3.xhtml]
+[test_bug752226-4.xhtml]
+[test_bug765993.html]
+[test_bug780199.xhtml]
+[test_bug780529.xhtml]
+[test_bug800386.xhtml]
+[test_bug816340.xhtml]
+[test_bug884693.xhtml]
+[test_bug914381.html]
+[test_bug990812.xhtml]
+[test_bug1063837.xhtml]
+[test_bug1139964.xhtml]
+[test_bug1209621.xhtml]
+[test_bug1346936.html]
+[test_chromeOuterWindowID.xhtml]
+support-files =
+ window_chromeOuterWindowID.xhtml
+[test_getElementsWithGrid.html]
+[test_custom_element_content.xhtml]
+[test_custom_element_ep.xhtml]
+[test_document-element-inserted.xhtml]
+support-files =
+ file_document-element-inserted.xhtml
+ file_document-element-inserted-inner.xhtml
+[test_domparsing.xhtml]
+[test_fileconstructor.xhtml]
+[test_input_value_set_preserve_undo.xhtml]
+[test_nsITextInputProcessor.xhtml]
+[test_permission_hasValidTransientUserActivation.xhtml]
+support-files = ../dummy.html
+[test_range_getClientRectsAndTexts.html]
+[test_title.xhtml]
+support-files = file_title.xhtml
+[test_windowroot.xhtml]
+[test_swapFrameLoaders.xhtml]
+skip-if = os == 'mac' # bug 1674413
+[test_bug1339722.html]
diff --git a/dom/base/test/chrome/clonedoc/chrome.manifest b/dom/base/test/chrome/clonedoc/chrome.manifest
new file mode 100644
index 0000000000..5d7e720416
--- /dev/null
+++ b/dom/base/test/chrome/clonedoc/chrome.manifest
@@ -0,0 +1 @@
+content clonedoc content/
diff --git a/dom/base/test/chrome/clonedoc/content/doc.xml b/dom/base/test/chrome/clonedoc/content/doc.xml
new file mode 100644
index 0000000000..fdd7e7c6e0
--- /dev/null
+++ b/dom/base/test/chrome/clonedoc/content/doc.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<something>
+ <somethinglese/>
+</something>
diff --git a/dom/base/test/chrome/custom_element_ep.js b/dom/base/test/chrome/custom_element_ep.js
new file mode 100644
index 0000000000..d933ecbbab
--- /dev/null
+++ b/dom/base/test/chrome/custom_element_ep.js
@@ -0,0 +1,14 @@
+/* globals finishTest */
+class XFoo extends HTMLElement {
+ constructor() {
+ super();
+ this.magicNumber = 42;
+ }
+
+ connectedCallback() {
+ finishTest(this.magicNumber === 42);
+ }
+}
+customElements.define("x-foo", XFoo);
+
+document.firstChild.appendChild(document.createElement("x-foo"));
diff --git a/dom/base/test/chrome/file_bug1139964.xhtml b/dom/base/test/chrome/file_bug1139964.xhtml
new file mode 100644
index 0000000000..8bf7f27e0b
--- /dev/null
+++ b/dom/base/test/chrome/file_bug1139964.xhtml
@@ -0,0 +1,60 @@
+<?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=1139964
+-->
+<window title="Mozilla Bug 1139964"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="run()">
+ <label value="Mozilla Bug 1139964"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage */
+ var ppm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService();
+
+ function ok(cond, msg) {
+ window.arguments[0].ok(cond, msg);
+ }
+
+ var msgName = "TEST:Global_has_Promise";
+
+ function mmScriptForPromiseTest() {
+ /* eslint-env mozilla/process-script */
+ sendAsyncMessage("TEST:Global_has_Promise",
+ {
+ hasPromise: ("Promise" in this),
+ hasTextEncoder: ("TextEncoder" in this),
+ hasWindow: ("Window" in this),
+ });
+ }
+
+ function processListener(m) {
+ ppm.removeMessageListener(msgName, processListener);
+ ok(m.data.hasPromise, "ProcessGlobal should have Promise object in the global scope!");
+ ok(m.data.hasTextEncoder, "ProcessGlobal should have TextEncoder object in the global scope!");
+ ok(m.data.hasWindow, "ProcessGlobal should have Window object in the global scope!");
+
+ messageManager.addMessageListener(msgName, tabListener)
+ messageManager.loadFrameScript("data:,(" + mmScriptForPromiseTest.toString() + ")()", true);
+ }
+
+ function tabListener(m) {
+ messageManager.removeMessageListener(msgName, tabListener);
+ ok(m.data.hasPromise, "BrowserChildGlobal should have Promise object in the global scope!");
+ ok(m.data.hasTextEncoder, "BrowserChildGlobal should have TextEncoder object in the global scope!");
+ ok(m.data.hasWindow, "BrowserChildGlobal should have Window object in the global scope!");
+
+ window.arguments[0].setTimeout(function() { this.done(); }, 0);
+ window.close();
+ }
+
+ function run() {
+ ppm.addMessageListener(msgName, processListener)
+ ppm.loadProcessScript("data:,(" + mmScriptForPromiseTest.toString() + ")()", true);
+ }
+
+ ]]></script>
+ <browser type="content" src="about:blank" id="ifr"/>
+</window>
diff --git a/dom/base/test/chrome/file_bug1209621.xhtml b/dom/base/test/chrome/file_bug1209621.xhtml
new file mode 100644
index 0000000000..3ba58975bd
--- /dev/null
+++ b/dom/base/test/chrome/file_bug1209621.xhtml
@@ -0,0 +1,85 @@
+<?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=1209621
+-->
+<window title="Mozilla Bug 1209621"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="run()">
+ <label value="Mozilla Bug 1209621"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ function ok(cond, msg) {
+ window.arguments[0].ok(cond, msg);
+ }
+
+ function is(actual, expected, msg) {
+ window.arguments[0].is(actual, expected, msg);
+ }
+
+ function run() {
+ var docshell = window.docShell;
+ ok(docshell, "Active window should have a DocShell");
+ var treeOwner = docshell.treeOwner;
+ ok(treeOwner, "Active docshell should have a TreeOwner!");
+
+ is(treeOwner.primaryContentShell, null,
+ "There shouldn't be primaryContentShell because no browser has primary=true.");
+ is(treeOwner.primaryRemoteTab, null,
+ "There shouldn't be primaryRemoteTab because no remote browser has primary=true.");
+ is(treeOwner.primaryContentBrowsingContext, null,
+ "There shouldn't be primaryContentBrowsingContext because no browser has primary=true.");
+
+ var ip = document.getElementById("inprocess");
+ var remote = document.getElementById("remote");
+ var remote2 = document.getElementById("remote2");
+
+ ip.setAttribute("primary", "true");
+ ok(ip.docShell, "non-remote browser should have a DocShell.");
+ is(treeOwner.primaryContentShell, ip.docShell,
+ "primary browser should be the primaryContentShell.");
+ is(treeOwner.primaryRemoteTab, null,
+ "There shouldn't be primaryRemoteTab because no remote browser has primary=true.");
+ is(treeOwner.primaryContentBrowsingContext, ip.browsingContext,
+ "primary browsing context should be the primaryContentBrowsingContext.");
+
+ ip.removeAttribute("primary");
+ remote.setAttribute("primary", "true");
+ is(treeOwner.primaryContentShell, null,
+ "There shouldn't be primaryContentShell because no browser has primary=true.");
+ var tp = remote.frameLoader.remoteTab;
+ ok(tp, "Remote browsers should have a remoteTab.");
+ is(treeOwner.primaryRemoteTab, tp,
+ "primary remote browser should be the primaryRemoteTab.");
+ is(treeOwner.primaryContentBrowsingContext, remote.browsingContext,
+ "primary remote browser should be the primaryContentBrowsingContext.");
+
+ remote.removeAttribute("primary");
+ is(treeOwner.primaryContentShell, null,
+ "There shouldn't be primaryContentShell because no browser has primary=true.");
+ is(treeOwner.primaryRemoteTab, null,
+ "There shouldn't be primaryRemoteTab because no remote browser has primary=true.");
+ is(treeOwner.primaryContentBrowsingContext, null,
+ "There shouldn't be primaryContentBrowsingContext because no browser has primary=true.");
+
+ remote2.setAttribute("primary", "true");
+ var tp2 = remote2.frameLoader.remoteTab;
+ ok(tp2, "Remote browsers should have a remoteTab.");
+ is(treeOwner.primaryRemoteTab, tp2,
+ "primary remote browser should be the primaryRemoteTab.");
+ is(treeOwner.primaryContentShell, null,
+ "There shouldn't be primaryContentShell because no browser has primary=true.");
+ is(treeOwner.primaryContentBrowsingContext, remote2.browsingContext,
+ "primary remote browser should be the primaryContentBrowsingContext.");
+
+ window.arguments[0].setTimeout(function() { this.done(); }, 0);
+ window.close();
+ }
+
+ ]]></script>
+ <browser type="content" src="about:blank" id="inprocess"/>
+ <browser type="content" remote="true" src="about:blank" id="remote"/>
+ <browser type="content" remote="true" src="about:blank" id="remote2"/>
+</window>
diff --git a/dom/base/test/chrome/file_bug549682.xhtml b/dom/base/test/chrome/file_bug549682.xhtml
new file mode 100644
index 0000000000..02919386c4
--- /dev/null
+++ b/dom/base/test/chrome/file_bug549682.xhtml
@@ -0,0 +1,214 @@
+<?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=549682
+-->
+<window title="Mozilla Bug 549682"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="run()">
+ <label value="Mozilla Bug 549682"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage */
+ var didRunAsync = false;
+ var didRunLocal = false;
+
+ var global = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+ var ppm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService();
+ var cpm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService();
+
+ function ok(cond, msg) {
+ window.arguments[0].ok(cond, msg);
+ }
+
+ function is(actual, expected, msg) {
+ window.arguments[0].is(actual, expected, msg);
+ }
+
+ var asyncPPML = false;
+ function ppmASL(m) {
+ asyncPPML = true;
+ }
+ var syncPPML = false;
+ function ppmSL(m) {
+ syncPPML = true;
+ }
+ ppm.addMessageListener("processmessageAsync", ppmASL);
+ ppm.addMessageListener("processmessageSync", ppmSL);
+
+ cpm.sendAsyncMessage("processmessageAsync", "");
+ cpm.sendSyncMessage("processmessageSync", "");
+
+ var asyncCPML = false;
+ function cpmASL(m) {
+ asyncCPML = true;
+ }
+ cpm.addMessageListener("childprocessmessage", cpmASL);
+ ppm.broadcastAsyncMessage("childprocessmessage", "");
+
+ function checkPMMMessages() {
+ ok(asyncPPML, "should have handled async message");
+ ok(syncPPML, "should have handled sync message");
+ ok(asyncCPML, "should have handled async message");
+ ppm.removeMessageListener("processmessageAsync", ppmASL);
+ ppm.removeMessageListener("processmessageSync", ppmSL);
+ cpm.removeMessageListener("childprocessmessage", cpmASL);
+ }
+
+ var globalListenerCallCount = 0;
+ function globalListener(m) {
+ ++globalListenerCallCount;
+ if (m.name == "sync") {
+ global.removeMessageListener("async", globalListener);
+ global.removeMessageListener("sync", globalListener);
+ global.removeMessageListener("global-sync", globalListener);
+ // Note, the result depends on what other windows are open.
+ ok(globalListenerCallCount >= 4,
+ "Global listener should have been called at least 4 times!");
+ ok(didRunLocal, "Local message received.");
+ }
+ }
+
+ function asyncL(m) {
+ didRunAsync = true;
+ is(m.name, "async", "Wrong message!");
+ is(m.json.data, 1234, "Wrong data!");
+ }
+
+ function syncL(m) {
+ is(m.name, "sync", "Wrong message!");
+ is(m.json.data, 1234, "Wrong data!");
+ ok(didRunAsync, "Should have run async!");
+ }
+
+ function localL(m) {
+ is(m.name, "lasync", "Wrong message!");
+ is(m.json.data, 2345, "Wrong data!");
+ didRunLocal = true;
+ }
+
+ var weakMessageReceived = false;
+ var weakListener = {
+ QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
+
+ receiveMessage: function(msg) {
+ if (weakMessageReceived) {
+ ok(false, 'Weak listener fired twice.');
+ return;
+ }
+
+ ok(true, 'Weak listener fired once.');
+ weakMessageReceived = true;
+ document.getElementById('ifr').messageManager
+ .removeWeakMessageListener('weak', weakListener);
+ }
+ };
+
+ var weakListener2 = {
+ QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
+
+ receiveMessage: function(msg) {
+ ok(false, 'Should not have received a message.');
+ }
+ };
+
+ function weakDoneListener() {
+ ok(weakMessageReceived, 'Got "weak" message.');
+ finish();
+ }
+
+ function finish() {
+ window.arguments[0].setTimeout(function() { this.done(); }, 0);
+ var i = document.getElementById("ifr");
+ i.remove(); // This is a crash test!
+ window.close();
+ }
+
+ function loadScript() {
+ // Async should be processed first!
+ messageManager.loadFrameScript("data:,\
+ sendAsyncMessage('async', { data: 1234 });\
+ sendSyncMessage('sync', { data: 1234 });\
+ sendAsyncMessage('weak', {});\
+ sendAsyncMessage('weak', {});\
+ sendAsyncMessage('weakdone', {});", false);
+ }
+
+ function run() {
+ var localmm = document.getElementById('ifr').messageManager;
+
+ var docShell = document.getElementById('ifr').contentWindow.docShell;
+ ok(docShell, "Should have docshell");
+ var cfmm = docShell.messageManager;
+ ok(cfmm, "Should have content messageManager");
+
+ var didGetSyncMessage = false;
+ function syncContinueTestFn() {
+ didGetSyncMessage = true;
+ }
+ localmm.addMessageListener("syncContinueTest", syncContinueTestFn);
+ cfmm.sendSyncMessage("syncContinueTest", {});
+ localmm.removeMessageListener("syncContinueTest", syncContinueTestFn);
+ ok(didGetSyncMessage, "Should have got sync message!");
+
+ localmm.addMessageListener("lasync", localL);
+ localmm.loadFrameScript("data:,sendAsyncMessage('lasync', { data: 2345 })", false);
+
+ messageManager.addMessageListener("async", asyncL);
+ messageManager.addMessageListener("sync", syncL);
+ global.addMessageListener("async", globalListener);
+ global.addMessageListener("sync", globalListener);
+ global.addMessageListener("global-sync", globalListener);
+ global.loadFrameScript("data:,sendSyncMessage('global-sync', { data: 1234 });", true);
+ var toBeRemovedScript = "data:,sendAsyncMessage('toberemoved', { data: 2345 })";
+ var c = 0;
+ messageManager.addMessageListener("toberemoved", function() {
+ ++c;
+ is(c, 1, "Should be called only once!");
+ });
+ // This loads the script in the existing <browser>
+ messageManager.loadFrameScript(toBeRemovedScript, true);
+ // But it won't be loaded in the dynamically created <browser>
+ messageManager.removeDelayedFrameScript(toBeRemovedScript);
+
+ var oldValue = globalListenerCallCount;
+ var b = document.createXULElement("browser");
+ b.setAttribute("type", "content");
+ document.documentElement.appendChild(b);
+ is(globalListenerCallCount, oldValue + 1,
+ "Wrong message count");
+
+ localmm.addWeakMessageListener('weak', weakListener);
+ localmm.addMessageListener('weakdone', weakDoneListener);
+
+ // Add weakListener2 as a weak message listener, then force weakListener2
+ // to be gc'ed. weakListener2 shouldn't be run.
+ var weakRef = Cu.getWeakReference(weakListener2);
+ localmm.addWeakMessageListener('weak', weakListener2);
+ weakListener2 = null;
+
+ // Force a gc/cc in a loop until weakRef's referent has gone away.
+ function waitForWeakRefToDie() {
+ if (weakRef.get()) {
+ var mgr = Cc["@mozilla.org/memory-reporter-manager;1"]
+ .getService(Ci.nsIMemoryReporterManager);
+ mgr.minimizeMemoryUsage(waitForWeakRefToDie);
+
+ // Print a message so that if the test hangs in a minimizeMemoryUsage
+ // loop, we'll be able to see it in the log.
+ ok(true, "waitForWeakRefToDie spinning...");
+ return;
+ }
+
+ setTimeout(checkPMMMessages, 0);
+ setTimeout(loadScript, 0);
+ }
+
+ waitForWeakRefToDie();
+ }
+
+ ]]></script>
+ <browser type="content" src="about:blank" id="ifr"/>
+</window>
diff --git a/dom/base/test/chrome/file_bug616841.xhtml b/dom/base/test/chrome/file_bug616841.xhtml
new file mode 100644
index 0000000000..a5e5d9a427
--- /dev/null
+++ b/dom/base/test/chrome/file_bug616841.xhtml
@@ -0,0 +1,63 @@
+<?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=616841
+-->
+<window title="Mozilla Bug 616841"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start()">
+ <label value="Mozilla Bug 616841"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage */
+ const FRAME_SCRIPT =
+"data:,addMessageListener(\n"+
+" 'cmp',\n"+
+" function (m) {\n"+
+" sendAsyncMessage('cmp', { i: m.json.i,\n"+
+" cmp: m.json.a.localeCompare(m.json.b) });\n"+
+" });\n"+
+"sendAsyncMessage('contentReady');";
+
+ var toCompare = [ [ "C", "D" ],
+ [ "D", "C" ],
+ [ "\u010C", "D" ],
+ [ "D", "\u010C" ] ];
+ var nCmps = 0;
+
+ function recvContentReady(m) {
+ for (var i = 0; i < toCompare.length; ++i) {
+ var pair = toCompare[i];
+ messageManager.broadcastAsyncMessage("cmp",
+ { i: i, a: pair[0], b: pair[1] });
+ }
+ }
+
+ function recvCmp(m) {
+ var i = m.json.i, cmp = m.json.cmp;
+ var pair = toCompare[i];
+ window.arguments[0].is(pair[0].localeCompare(pair[1]), cmp, "localeCompare returned same result in frame script");
+
+ if (toCompare.length == ++nCmps) {
+ messageManager.removeMessageListener("cmp", recvCmp);
+ finish();
+ }
+ }
+
+ function start() {
+ messageManager.addMessageListener("contentReady", recvContentReady);
+ messageManager.addMessageListener("cmp", recvCmp);
+ messageManager.loadFrameScript(FRAME_SCRIPT, true);
+ }
+
+ function finish() {
+ window.arguments[0].setTimeout(function() { this.done(); }, 0);
+ window.close();
+ }
+
+ ]]></script>
+
+ <browser id="browser" type="content" src="about:blank"/>
+</window>
diff --git a/dom/base/test/chrome/file_bug816340.xhtml b/dom/base/test/chrome/file_bug816340.xhtml
new file mode 100644
index 0000000000..2ee0ec3365
--- /dev/null
+++ b/dom/base/test/chrome/file_bug816340.xhtml
@@ -0,0 +1,70 @@
+<?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=816340
+-->
+<window title="Mozilla Bug 816340"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <label value="Mozilla Bug 816340"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ function ok(val, msg) {
+ window.arguments[0].ok(val, msg);
+ }
+
+ var elems =
+ [
+ "input",
+ "textarea",
+ "select",
+ "fieldset",
+ "button",
+ ];
+
+ var chromeDidGetEvent = false;
+ function chromeListener() {
+ chromeDidGetEvent = true;
+ }
+
+ function testElement(el, disabled, contentShouldGetEvent) {
+ chromeDidGetEvent = false;
+ var b = document.getElementById("browser");
+ b.contentDocument.body.innerHTML = null;
+ var e = b.contentDocument.createElement(el);
+ if (disabled) {
+ e.setAttribute("disabled", "true");
+ }
+ b.contentDocument.body.appendChild(e);
+ var contentDidGetEvent = false;
+ b.contentDocument.body.addEventListener("foo",
+ function() { contentDidGetEvent = true }, true);
+
+ b.addEventListener("foo", chromeListener, true);
+ e.dispatchEvent(new Event("foo"));
+ b.removeEventListener("foo", chromeListener, true);
+ ok(contentDidGetEvent == contentShouldGetEvent, "content: " + el + (disabled ? " disabled" : ""));
+ ok(chromeDidGetEvent, "chrome: " + el + (disabled ? " disabled" : ""));
+ }
+
+ function start() {
+ // Test common element.
+ testElement("div", false, true);
+ testElement("div", true, true);
+
+ for (var i = 0; i < elems.length; ++i) {
+ testElement(elems[i], false, true);
+ testElement(elems[i], true, false);
+ }
+ ok(true, "done");
+ window.arguments[0].setTimeout(function() { this.done(); }, 0);
+ window.close();
+ }
+
+ ]]></script>
+
+ <browser id="browser" type="content" src="about:blank"/>
+</window>
diff --git a/dom/base/test/chrome/file_bug990812-1.xhtml b/dom/base/test/chrome/file_bug990812-1.xhtml
new file mode 100644
index 0000000000..8b8da3d136
--- /dev/null
+++ b/dom/base/test/chrome/file_bug990812-1.xhtml
@@ -0,0 +1,61 @@
+<?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=990812
+-->
+<window title="Mozilla Bug 990812"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <label value="Mozilla Bug 990812"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage, getGroupMessageManager */
+ var FRAME_SCRIPT_GLOBAL = "data:,sendSyncMessage('test', 'global')";
+ var FRAME_SCRIPT_WINDOW = "data:,sendSyncMessage('test', 'window')";
+ var FRAME_SCRIPT_GROUP = "data:,sendSyncMessage('test', 'group')";
+
+ var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+
+ function is(val, exp, msg) {
+ window.arguments[0].is(val, exp, msg);
+ }
+
+ /**
+ * Ensures that delayed frame scripts are loaded in the expected order.
+ * Global frame scripts will be loaded before delayed frame scripts from
+ * window message managers. The latter will be loaded before group message
+ * manager frame scripts.
+ */
+ function start() {
+ globalMM.loadFrameScript(FRAME_SCRIPT_GLOBAL, true);
+ messageManager.loadFrameScript(FRAME_SCRIPT_WINDOW, true);
+ getGroupMessageManager("test").loadFrameScript(FRAME_SCRIPT_GROUP, true);
+
+ var order = ["global", "window", "group"];
+
+ messageManager.addMessageListener("test", function onMessage(msg) {
+ var next = order.shift();
+ window.arguments[0].is(msg.data, next, "received test:" + next);
+
+ if (!order.length) {
+ window.arguments[0].setTimeout(function() { this.next(); });
+ window.close();
+ }
+ });
+
+ var browser = document.createXULElement("browser");
+ browser.setAttribute("messagemanagergroup", "test");
+ browser.setAttribute("src", "about:mozilla");
+ browser.setAttribute("type", "content");
+ document.documentElement.appendChild(browser);
+
+ globalMM.removeDelayedFrameScript(FRAME_SCRIPT_GLOBAL);
+ messageManager.removeDelayedFrameScript(FRAME_SCRIPT_WINDOW);
+ getGroupMessageManager("test").removeDelayedFrameScript(FRAME_SCRIPT_GROUP);
+ }
+
+ ]]></script>
+
+</window>
diff --git a/dom/base/test/chrome/file_bug990812-2.xhtml b/dom/base/test/chrome/file_bug990812-2.xhtml
new file mode 100644
index 0000000000..e13b47f589
--- /dev/null
+++ b/dom/base/test/chrome/file_bug990812-2.xhtml
@@ -0,0 +1,56 @@
+<?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=990812
+-->
+<window title="Mozilla Bug 990812"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <label value="Mozilla Bug 990812"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage, getGroupMessageManager */
+ var FRAME_SCRIPT = "data:,sendAsyncMessage('test')";
+ var order = ["group", "window", "global"];
+
+ var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+
+ function is(val, exp, msg) {
+ window.arguments[0].is(val, exp, msg);
+ }
+
+ function promiseMessage(type, mm) {
+ return new Promise(function (resolve) {
+ mm.addMessageListener("test", function onMessage() {
+ mm.removeMessageListener("test", onMessage);
+ is(type, order.shift(), "correct type " + type);
+ resolve();
+ });
+ });
+ }
+
+ /**
+ * Tests that async messages sent by frame scripts bubble up as expected,
+ * passing the group, window, and global message managers in that order.
+ */
+ function start() {
+ var global = promiseMessage("global", globalMM);
+ var window = promiseMessage("window", messageManager);
+ var group = promiseMessage("group", getGroupMessageManager("test"));
+
+ var browser = document.querySelector("browser");
+ browser.messageManager.loadFrameScript(FRAME_SCRIPT, true);
+
+ Promise.all([global, window, group]).then(function () {
+ self.arguments[0].setTimeout(function() { this.next(); });
+ self.close();
+ });
+ }
+
+ ]]></script>
+
+ <browser messagemanagergroup="test" type="content" src="about:mozilla" />
+
+</window>
diff --git a/dom/base/test/chrome/file_bug990812-3.xhtml b/dom/base/test/chrome/file_bug990812-3.xhtml
new file mode 100644
index 0000000000..1f3e1d69f2
--- /dev/null
+++ b/dom/base/test/chrome/file_bug990812-3.xhtml
@@ -0,0 +1,68 @@
+<?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=990812
+-->
+<window title="Mozilla Bug 990812"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <label value="Mozilla Bug 990812"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage, getGroupMessageManager */
+ var FRAME_SCRIPT = "data:,addMessageListener('test', function (msg) {" +
+ "sendSyncMessage('test', msg.data)})";
+
+ var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+
+ function is(val, exp, msg) {
+ window.arguments[0].is(val, exp, msg);
+ }
+
+ function promiseMessage(type, mm) {
+ var order = [type, "window", "global"];
+
+ return new Promise(function (resolve) {
+ mm.addMessageListener("test", function onMessage(msg) {
+ is(msg.data, order.shift(), "correct message " + msg.data);
+
+ if (!order.length) {
+ mm.removeMessageListener("test", onMessage);
+ resolve();
+ }
+ });
+ });
+ }
+
+ /**
+ * Ensures that broadcasting an async message does only reach descendants
+ * of a specific message manager and respects message manager groups.
+ */
+ function start() {
+ var mm1 = document.querySelector("browser").messageManager;
+ var promise1 = promiseMessage("group1", mm1);
+ mm1.loadFrameScript(FRAME_SCRIPT, true);
+
+ var mm2 = document.querySelector("browser + browser").messageManager;
+ var promise2 = promiseMessage("group2", mm2);
+ mm2.loadFrameScript(FRAME_SCRIPT, true);
+
+ getGroupMessageManager("test1").broadcastAsyncMessage("test", "group1");
+ getGroupMessageManager("test2").broadcastAsyncMessage("test", "group2");
+ messageManager.broadcastAsyncMessage("test", "window");
+ globalMM.broadcastAsyncMessage("test", "global");
+
+ Promise.all([promise1, promise2]).then(function () {
+ window.arguments[0].setTimeout(function() { this.next(); });
+ window.close();
+ });
+ }
+
+ ]]></script>
+
+ <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
+ <browser messagemanagergroup="test2" type="content" src="about:mozilla" />
+
+</window>
diff --git a/dom/base/test/chrome/file_bug990812-4.xhtml b/dom/base/test/chrome/file_bug990812-4.xhtml
new file mode 100644
index 0000000000..1c16ceb02c
--- /dev/null
+++ b/dom/base/test/chrome/file_bug990812-4.xhtml
@@ -0,0 +1,63 @@
+<?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=990812
+-->
+<window title="Mozilla Bug 990812"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <label value="Mozilla Bug 990812"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage, getGroupMessageManager */
+ var FRAME_SCRIPT1 = "data:,addMessageListener('test', function () {" +
+ "sendSyncMessage('test', 'frame1')})";
+ var FRAME_SCRIPT2 = "data:,addMessageListener('test', function () {" +
+ "sendSyncMessage('test', 'frame2')})";
+
+ var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+
+ function is(val, exp, msg) {
+ window.arguments[0].is(val, exp, msg);
+ }
+
+ function promiseMessage(type, mm) {
+ return new Promise(function (resolve) {
+ mm.addMessageListener("test", function onMessage(msg) {
+ mm.removeMessageListener("test", onMessage);
+ is(msg.data, type, "correct message " + type);
+ resolve();
+ });
+ });
+ }
+
+ /**
+ * Tests that swapping docShells works as expected wrt to groups.
+ */
+ function start() {
+ var browser1 = document.querySelector("browser");
+ browser1.messageManager.loadFrameScript(FRAME_SCRIPT1, true);
+
+ var browser2 = document.querySelector("browser + browser");
+ browser2.messageManager.loadFrameScript(FRAME_SCRIPT2, true);
+
+ var promise1 = promiseMessage("frame2", getGroupMessageManager("test1"));
+ var promise2 = promiseMessage("frame1", getGroupMessageManager("test2"));
+
+ browser1.swapFrameLoaders(browser2);
+ messageManager.broadcastAsyncMessage("test");
+
+ Promise.all([promise1, promise2]).then(function () {
+ window.arguments[0].setTimeout(function() { this.next(); });
+ window.close();
+ });
+ }
+
+ ]]></script>
+
+ <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
+ <browser messagemanagergroup="test2" type="content" src="about:mozilla" />
+
+</window>
diff --git a/dom/base/test/chrome/file_bug990812-5.xhtml b/dom/base/test/chrome/file_bug990812-5.xhtml
new file mode 100644
index 0000000000..8c418492a1
--- /dev/null
+++ b/dom/base/test/chrome/file_bug990812-5.xhtml
@@ -0,0 +1,74 @@
+<?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=990812
+-->
+<window title="Mozilla Bug 990812"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <label value="Mozilla Bug 990812"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage, getGroupMessageManager */
+ var FRAME_SCRIPT1 = "data:,addMessageListener('test', function () {" +
+ "sendSyncMessage('test', 'group1')})";
+ var FRAME_SCRIPT2 = "data:,addMessageListener('test', function () {" +
+ "sendSyncMessage('test', 'group2')})";
+
+ var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+
+ function is(val, exp, msg) {
+ window.arguments[0].is(val, exp, msg);
+ }
+
+ function promiseTwoMessages(type, mm) {
+ var numLeft = 2;
+
+ return new Promise(function (resolve) {
+ mm.addMessageListener("test", function onMessage(msg) {
+ is(msg.data, type, "correct message " + type);
+
+ if (--numLeft == 0) {
+ mm.removeMessageListener("test", onMessage);
+ resolve();
+ }
+ });
+ });
+ }
+
+ /**
+ * This test ensures that having multiple message manager groups with
+ * multiple frame loaders in those works as expected. For a specific
+ * group message manager, frame scripts should only be loaded by its
+ * descendants and messages should only be received by and from those
+ * child message managers.
+ */
+ function start() {
+ var gmm1 = getGroupMessageManager("test1");
+ gmm1.loadFrameScript(FRAME_SCRIPT1, true);
+
+ var gmm2 = getGroupMessageManager("test2");
+ gmm2.loadFrameScript(FRAME_SCRIPT2, true);
+
+ var promise1 = promiseTwoMessages("group1", gmm1);
+ var promise2 = promiseTwoMessages("group2", gmm2);
+
+ messageManager.broadcastAsyncMessage("test");
+
+ Promise.all([promise1, promise2]).then(function () {
+ window.arguments[0].setTimeout(function() { this.next(); });
+ window.close();
+ });
+ }
+
+ ]]></script>
+
+ <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
+ <browser messagemanagergroup="test1" type="content" src="about:mozilla" />
+
+ <browser messagemanagergroup="test2" type="content" src="about:mozilla" />
+ <browser messagemanagergroup="test2" type="content" src="about:mozilla" />
+
+</window>
diff --git a/dom/base/test/chrome/file_bug990812.xhtml b/dom/base/test/chrome/file_bug990812.xhtml
new file mode 100644
index 0000000000..02662d5749
--- /dev/null
+++ b/dom/base/test/chrome/file_bug990812.xhtml
@@ -0,0 +1,55 @@
+<?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=990812
+-->
+<window title="Mozilla Bug 990812"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <label value="Mozilla Bug 990812"/>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /* global messageManager, sendAsyncMessage, getGroupMessageManager */
+ var FRAME_SCRIPT_GLOBAL = "data:,sendSyncMessage('test', 'global')";
+ var FRAME_SCRIPT_WINDOW = "data:,sendSyncMessage('test', 'window')";
+ var FRAME_SCRIPT_GROUP = "data:,sendSyncMessage('test', 'group')";
+
+ var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+
+ function is(val, exp, msg) {
+ opener.wrappedJSObject.is(val, exp, msg);
+ }
+
+ function start() {
+ globalMM.loadFrameScript(FRAME_SCRIPT_GLOBAL, true);
+ messageManager.loadFrameScript(FRAME_SCRIPT_WINDOW, true);
+ getGroupMessageManager("test").loadFrameScript(FRAME_SCRIPT_GROUP, true);
+
+ var order = ["global", "window", "group"];
+
+ messageManager.addMessageListener("test", function onMessage(msg) {
+ var next = order.shift();
+ opener.wrappedJSObject.is(msg.data, next, "received test:" + next);
+
+ if (!order.length) {
+ opener.setTimeout("next()");
+ window.close();
+ }
+ });
+
+ var browser = document.createXULElement("browser");
+ browser.setAttribute("messagemanagergroup", "test");
+ browser.setAttribute("src", "about:mozilla");
+ browser.setAttribute("type", "content");
+ document.documentElement.appendChild(browser);
+
+ globalMM.removeDelayedFrameScript(FRAME_SCRIPT_GLOBAL);
+ messageManager.removeDelayedFrameScript(FRAME_SCRIPT_WINDOW);
+ getGroupMessageManager("test").removeDelayedFrameScript(FRAME_SCRIPT_GROUP);
+ }
+
+ ]]></script>
+
+</window>
diff --git a/dom/base/test/chrome/file_document-element-inserted-inner.xhtml b/dom/base/test/chrome/file_document-element-inserted-inner.xhtml
new file mode 100644
index 0000000000..2088e2789a
--- /dev/null
+++ b/dom/base/test/chrome/file_document-element-inserted-inner.xhtml
@@ -0,0 +1 @@
+<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'></window> \ No newline at end of file
diff --git a/dom/base/test/chrome/file_document-element-inserted.xhtml b/dom/base/test/chrome/file_document-element-inserted.xhtml
new file mode 100644
index 0000000000..d67df13df7
--- /dev/null
+++ b/dom/base/test/chrome/file_document-element-inserted.xhtml
@@ -0,0 +1,3 @@
+<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'>
+ <iframe src='file_document-element-inserted-inner.xhtml'></iframe>
+</window> \ No newline at end of file
diff --git a/dom/base/test/chrome/file_title.xhtml b/dom/base/test/chrome/file_title.xhtml
new file mode 100644
index 0000000000..d1b04418aa
--- /dev/null
+++ b/dom/base/test/chrome/file_title.xhtml
@@ -0,0 +1 @@
+<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul' title='Test'/>
diff --git a/dom/base/test/chrome/fileconstructor_file.png b/dom/base/test/chrome/fileconstructor_file.png
new file mode 100644
index 0000000000..51e8aaf38c
--- /dev/null
+++ b/dom/base/test/chrome/fileconstructor_file.png
Binary files differ
diff --git a/dom/base/test/chrome/frame_custom_element_content.html b/dom/base/test/chrome/frame_custom_element_content.html
new file mode 100644
index 0000000000..aa1d75863d
--- /dev/null
+++ b/dom/base/test/chrome/frame_custom_element_content.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<x-bar></x-bar>
+</body>
+</html>
diff --git a/dom/base/test/chrome/nochrome_bug1346936.html b/dom/base/test/chrome/nochrome_bug1346936.html
new file mode 100644
index 0000000000..158b20c884
--- /dev/null
+++ b/dom/base/test/chrome/nochrome_bug1346936.html
@@ -0,0 +1,3 @@
+<!DOCTYPE HTML>
+<html>
+</html>
diff --git a/dom/base/test/chrome/nochrome_bug1346936.js b/dom/base/test/chrome/nochrome_bug1346936.js
new file mode 100644
index 0000000000..a84113e1e1
--- /dev/null
+++ b/dom/base/test/chrome/nochrome_bug1346936.js
@@ -0,0 +1,4 @@
+//# sourceMappingURL=bar.js.map
+
+// Define a single function to prevent script source from being gc'd
+function foo() {}
diff --git a/dom/base/test/chrome/nochrome_bug1346936.js^headers^ b/dom/base/test/chrome/nochrome_bug1346936.js^headers^
new file mode 100644
index 0000000000..812264590d
--- /dev/null
+++ b/dom/base/test/chrome/nochrome_bug1346936.js^headers^
@@ -0,0 +1 @@
+SourceMap: foo.js.map
diff --git a/dom/base/test/chrome/nochrome_bug765993.html b/dom/base/test/chrome/nochrome_bug765993.html
new file mode 100644
index 0000000000..158b20c884
--- /dev/null
+++ b/dom/base/test/chrome/nochrome_bug765993.html
@@ -0,0 +1,3 @@
+<!DOCTYPE HTML>
+<html>
+</html>
diff --git a/dom/base/test/chrome/nochrome_bug765993.js b/dom/base/test/chrome/nochrome_bug765993.js
new file mode 100644
index 0000000000..a84113e1e1
--- /dev/null
+++ b/dom/base/test/chrome/nochrome_bug765993.js
@@ -0,0 +1,4 @@
+//# sourceMappingURL=bar.js.map
+
+// Define a single function to prevent script source from being gc'd
+function foo() {}
diff --git a/dom/base/test/chrome/nochrome_bug765993.js^headers^ b/dom/base/test/chrome/nochrome_bug765993.js^headers^
new file mode 100644
index 0000000000..8efacff3c8
--- /dev/null
+++ b/dom/base/test/chrome/nochrome_bug765993.js^headers^
@@ -0,0 +1 @@
+X-SourceMap: foo.js.map
diff --git a/dom/base/test/chrome/test_bug1063837.xhtml b/dom/base/test/chrome/test_bug1063837.xhtml
new file mode 100644
index 0000000000..794cf1c72c
--- /dev/null
+++ b/dom/base/test/chrome/test_bug1063837.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=206691
+-->
+<window title="Mozilla Bug 1063837"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=1063837"
+ target="_blank">Mozilla Bug 1063837</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 1063837 **/
+ SimpleTest.waitForExplicitFinish();
+
+ addLoadEvent(function() {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", location, false);
+ xhr.onload = function() {
+ ok(xhr.responseXML, "We should have response content!");
+ var principal = xhr.responseXML.nodePrincipal;
+ ok(principal.schemeIs("moz-nullprincipal"), "The response document should have a null principal");
+ SimpleTest.finish();
+ }
+ xhr.send();
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug1098074_throw_from_ReceiveMessage.xhtml b/dom/base/test/chrome/test_bug1098074_throw_from_ReceiveMessage.xhtml
new file mode 100644
index 0000000000..dbedb59abe
--- /dev/null
+++ b/dom/base/test/chrome/test_bug1098074_throw_from_ReceiveMessage.xhtml
@@ -0,0 +1,46 @@
+<?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=1098074
+-->
+<window title="Mozilla Bug 1098074"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 1098074 **/
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.expectUncaughtException();
+
+ // Tell the test to expect exactly one console error with the given parameters,
+ // with SimpleTest.finish as a continuation function.
+ SimpleTest.monitorConsole(SimpleTest.finish, [{errorMessage: new RegExp('acopia')}]);
+
+ var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService();
+ globalMM.addMessageListener("flimfniffle", function onMessage(msg) {
+ globalMM.removeMessageListener("flimfniffle", onMessage);
+ is(msg.data, "teufeltor", "correct message");
+
+ // Cleanup the monitor after we throw.
+ SimpleTest.executeSoon(SimpleTest.endMonitorConsole);
+
+ throw "acopia";
+ });
+
+ function start() {
+ globalMM.loadFrameScript("data:,sendAsyncMessage('flimfniffle', 'teufeltor')", true);
+ }
+
+ ]]>
+ </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=1098074"
+ target="_blank">Mozilla Bug 1098074</a>
+ </body>
+</window>
diff --git a/dom/base/test/chrome/test_bug1139964.xhtml b/dom/base/test/chrome/test_bug1139964.xhtml
new file mode 100644
index 0000000000..8b1b36fa64
--- /dev/null
+++ b/dom/base/test/chrome/test_bug1139964.xhtml
@@ -0,0 +1,32 @@
+<?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=1139964
+-->
+<window title="Mozilla Bug 1139964"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=1139964"
+ target="_blank">Mozilla Bug 1139964</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 1139964 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function done() {
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(function() {
+ window.openDialog("file_bug1139964.xhtml", "", "chrome,noopener", window);
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug120684.xhtml b/dom/base/test/chrome/test_bug120684.xhtml
new file mode 100644
index 0000000000..08e9b28cfe
--- /dev/null
+++ b/dom/base/test/chrome/test_bug120684.xhtml
@@ -0,0 +1,80 @@
+<?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=120684
+-->
+<window title="Mozilla Bug 120684"
+ 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=120684"
+ target="_blank">Mozilla Bug 120684</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 120684 **/
+
+ var list = new ChromeNodeList();
+ is(list.length, 0, "Length should be initially 0.");
+
+ ok(NodeList.isInstance(list), "ChromeNodeList object should be an instance of NodeList.");
+
+ try {
+ list.append(document);
+ ok(false, "should have throw!");
+ } catch(ex) {
+ ok(true, "ChromeNodeList supports only nsIContent objects for now.");
+ }
+
+ try {
+ list.remove(document);
+ ok(false, "should have throw!");
+ } catch(ex) {
+ ok(true, "ChromeNodeList supports only nsIContent objects for now.");
+ }
+ is(list.length, 0, "Length should be 0.");
+
+ list.append(document.documentElement);
+ is(list.length, 1, "Length should be 1.");
+ is(list[0], document.documentElement);
+ is(list[1], undefined);
+
+ // Removing element which isn't in the list shouldn't do anything.
+ list.remove(document.createXULElement("foo"));
+ is(list.length, 1, "Length should be 1.");
+ is(list[0], document.documentElement);
+
+ list.remove(document.documentElement);
+ is(list.length, 0, "Length should be 0.");
+ is(list[0], undefined);
+
+ var e1 = document.createXULElement("foo");
+ var e2 = document.createXULElement("foo");
+ var e3 = document.createXULElement("foo");
+
+ list.append(e1);
+ list.append(e2);
+ list.append(e3);
+
+ is(list[0], e1);
+ is(list[1], e2);
+ is(list[2], e3);
+ is(list.length, 3);
+
+ list.remove(e2);
+ is(list[0], e1);
+ is(list[1], e3);
+ is(list[2], undefined);
+ is(list.length, 2);
+
+ // A leak test.
+ list.expando = list;
+
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug1209621.xhtml b/dom/base/test/chrome/test_bug1209621.xhtml
new file mode 100644
index 0000000000..947606b638
--- /dev/null
+++ b/dom/base/test/chrome/test_bug1209621.xhtml
@@ -0,0 +1,34 @@
+<?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=1209621
+-->
+<window title="Mozilla Bug 1209621"
+ 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=1209621"
+ target="_blank">Mozilla Bug 1209621</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 1209621 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function done() {
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(function() {
+ window.openDialog("file_bug1209621.xhtml", "", "chrome,noopener", window);
+ });
+
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug1339722.html b/dom/base/test/chrome/test_bug1339722.html
new file mode 100644
index 0000000000..d8d95f1faa
--- /dev/null
+++ b/dom/base/test/chrome/test_bug1339722.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html>
+ <!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1339722
+-->
+ <head>
+ <meta charset="utf-8" />
+ <title>Test for Bug 1339722</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 1339722
+ * 1. Wait for "http-on-modify-request" or document-on-modify-request for the
+ * iframe load.
+ * 2. In the observer, access it's window proxy to trigger DOMWindowCreated.
+ * 3. In the event handler, delete the iframe so that the frameloader would be
+ * destroyed in the middle of ReallyStartLoading.
+ * 4. Verify that it doesn't crash.
+ **/
+
+ // This topic used to be http-on-useragent-request, but that got removed in
+ // bug 1513574. on-modify-request is called around the same time, and should
+ // behave similarly.
+ const TOPIC = "document-on-modify-request";
+ let win;
+ const observe = (subject, topic, data) => {
+ info("Got " + topic);
+ Services.obs.removeObserver(observe, TOPIC);
+
+ // Query window proxy so it triggers DOMWindowCreated.
+ let channel;
+ try {
+ // We need to QI nsIHttpChannel in order to load the interface's
+ // methods / attributes for later code that could assume we are dealing
+ // with a nsIHttpChannel.
+ channel = subject.QueryInterface(Ci.nsIHttpChannel);
+ } catch (e) {
+ channel = subject.QueryInterface(Ci.nsIIdentChannel);
+ }
+ win = channel.notificationCallbacks.getInterface(Ci.mozIDOMWindowProxy);
+ };
+
+ Services.obs.addObserver(observe, TOPIC);
+
+ let docShell = SpecialPowers.wrap(window).docShell;
+ docShell.chromeEventHandler.addEventListener(
+ "DOMWindowCreated",
+ function handler(e) {
+ info("Got DOMWindowCreated");
+ let iframe = document.getElementById("testFrame");
+ is(e.target, iframe.contentDocument, "verify event target");
+
+ // Remove the iframe to cause frameloader destroy.
+ iframe.remove();
+ setTimeout($ => {
+ ok(!document.getElementById("testFrame"), "verify iframe removed");
+ SimpleTest.finish();
+ }, 0);
+ },
+ { once: true }
+ );
+
+ SimpleTest.waitForExplicitFinish();
+ </script>
+ </head>
+ <body>
+ <a
+ target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1339722"
+ >Mozilla Bug 1339722</a
+ >
+ <p id="display"></p>
+ <div id="content" style="display: none;"></div>
+ <pre id="test">
+ <div id="frameContainer">
+ <iframe id="testFrame" src="http://www.example.com"></iframe>
+ </div>
+</pre>
+ </body>
+</html>
diff --git a/dom/base/test/chrome/test_bug1346936.html b/dom/base/test/chrome/test_bug1346936.html
new file mode 100644
index 0000000000..2c61c65237
--- /dev/null
+++ b/dom/base/test/chrome/test_bug1346936.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1346936
+-->
+<head>
+ <title>Test for Bug 1346936</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" 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=1346936">Mozilla Bug 1346936</a>
+<style type="text/css">
+#link1 a { user-select:none; }
+</style>
+<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
+<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1346936 **/
+
+const {addDebuggerToGlobal} = ChromeUtils.importESModule("resource://gre/modules/jsdebugger.sys.mjs");
+addDebuggerToGlobal(globalThis);
+
+window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ var iframe = document.createElement("iframe");
+ iframe.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.html";
+ iframe.onload = function() {
+ var script = iframe.contentWindow.document.createElement("script");
+ script.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.js";
+ script.onload = function() {
+ var dbg = new Debugger(iframe.contentWindow);
+ ok(dbg, "Should be able to create debugger");
+
+ var scripts = dbg.findScripts({
+ url: "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug1346936.js",
+ });
+ ok(scripts.length, "Should be able to find script");
+
+ is(scripts[0].source.sourceMapURL, "foo.js.map");
+ SimpleTest.finish();
+ };
+
+ iframe.contentWindow.document.body.appendChild(script);
+ };
+
+ document.body.appendChild(iframe);
+};
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/chrome/test_bug206691.xhtml b/dom/base/test/chrome/test_bug206691.xhtml
new file mode 100644
index 0000000000..16a27762ac
--- /dev/null
+++ b/dom/base/test/chrome/test_bug206691.xhtml
@@ -0,0 +1,32 @@
+<?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=206691
+-->
+<window title="Mozilla Bug 206691"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=206691"
+ target="_blank">Mozilla Bug 206691</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 206691 **/
+ SimpleTest.waitForExplicitFinish();
+
+ addLoadEvent(function() {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", location, false);
+ xhr.send();
+ ok(xhr.responseText, "We should have response content!");
+ SimpleTest.finish();
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug289714.xhtml b/dom/base/test/chrome/test_bug289714.xhtml
new file mode 100644
index 0000000000..4b4cc6fb84
--- /dev/null
+++ b/dom/base/test/chrome/test_bug289714.xhtml
@@ -0,0 +1,33 @@
+<?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=289714
+-->
+<window title="Mozilla Bug 289714"
+ 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=289714"
+ target="_blank">Mozilla Bug 289714</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /** Test for Bug 289714 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ let xhr = new XMLHttpRequest();
+ xhr.responseType = "document";
+ xhr.open("GET", "data:text/xml,<xml");
+ ok(xhr.channel !== undefined, "System XHRs should be privileged");
+ xhr.onload = () => {
+ ok(xhr.responseXML !== null, "System XHRs should yield <parsererrors>");
+ SimpleTest.finish();
+ };
+ xhr.send();
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug339494.xhtml b/dom/base/test/chrome/test_bug339494.xhtml
new file mode 100644
index 0000000000..9922c41b66
--- /dev/null
+++ b/dom/base/test/chrome/test_bug339494.xhtml
@@ -0,0 +1,62 @@
+<?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=339494
+-->
+<window title="Mozilla Bug 339494"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:xul="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=339494">Mozilla Bug 339494</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <xul:hbox id="d"/>
+ <xul:hbox id="s"/>
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+
+/** Test for Bug 339494 **/
+
+ var d = document.getElementById("d");
+
+ d.setAttribute("hhh", "testvalue");
+
+ document.addEventListener("DOMAttrModified", removeItAgain, false);
+ d.removeAttribute("hhh");
+ document.removeEventListener("DOMAttrModified", removeItAgain, false);
+
+ function removeItAgain()
+ {
+ ok(!d.hasAttribute("hhh"), "Value check 1. There should be no value");
+ isnot(d.getAttribute("hhh"), "testvalue", "Value check 2");
+ document.removeEventListener("DOMAttrModified", removeItAgain, false);
+ d.removeAttribute("hhh");
+ ok(true, "Reachability. We shouldn't have crashed");
+ }
+
+ var s = document.getElementById("s");
+
+ s.setAttribute("ggg", "testvalue");
+
+ document.addEventListener("DOMAttrModified", compareVal, false);
+ s.setAttribute("ggg", "othervalue");
+ document.removeEventListener("DOMAttrModified", compareVal, false);
+
+ function compareVal()
+ {
+ ok(s.hasAttribute("ggg"), "Value check 3. There should be a value");
+ isnot(s.getAttribute("ggg"), "testvalue", "Value check 4");
+ is(s.getAttribute("ggg"), "othervalue", "Value check 5");
+ }
+
+</script>
+
+</window>
diff --git a/dom/base/test/chrome/test_bug357450.xhtml b/dom/base/test/chrome/test_bug357450.xhtml
new file mode 100644
index 0000000000..7723364ecc
--- /dev/null
+++ b/dom/base/test/chrome/test_bug357450.xhtml
@@ -0,0 +1,56 @@
+<?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=357450
+-->
+
+<window title="Mozilla Bug 357450"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <!-- This file is shared with non-chrome tests -->
+ <script type="text/javascript" src="file_bug357450.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=357450"
+ target="_blank">Mozilla Bug 357450</a>
+
+<p id="display"></p>
+
+<div id="content" style="display: block">
+ <a class="classtest" name="nametest">hmm</a>
+ <b class="foo">hmm</b>
+ <b id="test1" class="test1">hmm</b>
+ <b id="test2" class="test2">hmm</b>
+ <b id="int-class" class="1">hmm</b>
+ <div id="example">
+ <p id="p1" class="aaa bbb"/>
+ <p id="p2" class="aaa ccc"/>
+ <p id="p3" class="bbb ccc"/>
+ </div>
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<svg xmlns="http://www.w3.org/2000/svg"
+ height="100" width="100" style="float:left">
+
+ <path d="M38,38c0-12,24-15,23-2c0,9-16,13-16,23v7h11v-4c0-9,17-12,17-27c-2-22-45-22-45,3zM45,70h11v11h-11z" fill="#371"/>
+
+ <circle cx="50" cy="50" r="45" class="classtest"
+ fill="none" stroke="#371" stroke-width="10"/>
+
+</svg>
+
+<xul:label class="classtest"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ hmm
+</xul:label>
+
+
+</window>
diff --git a/dom/base/test/chrome/test_bug380418.html b/dom/base/test/chrome/test_bug380418.html
new file mode 100644
index 0000000000..eb3f8d3042
--- /dev/null
+++ b/dom/base/test/chrome/test_bug380418.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=380418 -->
+<head>
+ <title>Test for Bug 380418</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.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=380418">Mozilla Bug 380418</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ var xhrPath = "http://mochi.test:8888" +
+ window.location.pathname.substring("/content".length);
+
+ var request = new XMLHttpRequest();
+ request.open("GET", xhrPath, false);
+ request.send(null);
+
+ // Try reading headers in privileged context
+ is(request.getResponseHeader("Set-Cookie"), "test", "Reading Set-Cookie response header in privileged context");
+ is(request.getResponseHeader("Set-Cookie2"), "test2", "Reading Set-Cookie2 response header in privileged context");
+ is(request.getResponseHeader("X-Dummy"), "test", "Reading X-Dummy response header in privileged context");
+
+ ok(/\bSet-Cookie:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie in all response headers in privileged context");
+ ok(/\bSet-Cookie2:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie2 in all response headers in privileged context");
+ ok(/\bX-Dummy:/i.test(request.getAllResponseHeaders()), "Looking for X-Dummy in all response headers in privileged context");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/chrome/test_bug380418.html^headers^ b/dom/base/test/chrome/test_bug380418.html^headers^
new file mode 100644
index 0000000000..5f8d4969c0
--- /dev/null
+++ b/dom/base/test/chrome/test_bug380418.html^headers^
@@ -0,0 +1,4 @@
+Set-Cookie: test
+Set-Cookie2: test2
+X-Dummy: test
+Cache-Control: max-age=0
diff --git a/dom/base/test/chrome/test_bug383430.html b/dom/base/test/chrome/test_bug383430.html
new file mode 100644
index 0000000000..ce526ef281
--- /dev/null
+++ b/dom/base/test/chrome/test_bug383430.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=383430
+-->
+<head>
+ <title>Test for Bug 383430</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.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=383430">Mozilla Bug 383430</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 383430 **/
+
+var req = new XMLHttpRequest();
+req.open("GET", window.location.href);
+req.send(null);
+
+ok(req.channel.loadGroup != null, "loadGroup is not null");
+
+req = new XMLHttpRequest();
+req.mozBackgroundRequest = true;
+req.open("GET", window.location.href);
+req.send(null);
+
+ok(req.channel.loadGroup == null, "loadGroup is null");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/chrome/test_bug418986-1.xhtml b/dom/base/test/chrome/test_bug418986-1.xhtml
new file mode 100644
index 0000000000..7d3add900a
--- /dev/null
+++ b/dom/base/test/chrome/test_bug418986-1.xhtml
@@ -0,0 +1,25 @@
+<?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=418986-1
+-->
+<window title="Mozilla Bug 418986 (Part 1)"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=418986-1"
+ target="_blank">Mozilla Bug 418986 (Part 1)</a>
+
+ <script type="application/javascript" src="bug418986-1.js"></script>
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ window.onload = function() {
+ test(false);
+ };
+ ]]></script>
+ </body>
+</window>
diff --git a/dom/base/test/chrome/test_bug421622.xhtml b/dom/base/test/chrome/test_bug421622.xhtml
new file mode 100644
index 0000000000..236c42dd34
--- /dev/null
+++ b/dom/base/test/chrome/test_bug421622.xhtml
@@ -0,0 +1,34 @@
+<?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=421622
+-->
+<window title="Mozilla Bug 421622"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=421622"
+ target="_blank">Mozilla Bug 421622</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 421622 **/
+ const SJS_URL = "http://mochi.test:8888/tests/dom/base/test/chrome/bug421622-referer.sjs";
+ const REFERER_URL = "http://www.mozilla.org/";
+
+ var req = new XMLHttpRequest();
+ req.open("GET", SJS_URL, false);
+ req.setRequestHeader("Referer", REFERER_URL);
+ req.send(null);
+
+ is(req.responseText,
+ "Referer: " + REFERER_URL,
+ "Referer header received by server does not match what was set");
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug429785.xhtml b/dom/base/test/chrome/test_bug429785.xhtml
new file mode 100644
index 0000000000..f4f6b414b4
--- /dev/null
+++ b/dom/base/test/chrome/test_bug429785.xhtml
@@ -0,0 +1,55 @@
+<?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=429785
+-->
+<window title="Mozilla Bug 429785"
+ 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=429785"
+ target="_blank">Mozilla Bug 429785</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /** Test for Bug 429785 **/
+ SimpleTest.waitForExplicitFinish();
+ var errorLogged = false;
+ const serv = Cc["@mozilla.org/consoleservice;1"]
+ .getService(Ci.nsIConsoleService);
+ var listener = {
+ QueryInterface: ChromeUtils.generateQI(["nsIConsoleListener"]),
+ observe : function (msg) { errorLogged = true; }
+ };
+
+ function step2() {
+ is(errorLogged, false, "Should be no errors");
+
+ serv.logStringMessage("This is a test");
+
+ setTimeout(step3, 0);
+
+ }
+
+ function step3() {
+ is(errorLogged, true, "Should see errors when they happen");
+ serv.unregisterListener(listener);
+ SimpleTest.finish();
+ }
+
+ serv.registerListener(listener);
+
+ var p = new DOMParser();
+ p.parseFromString("<root/>", "application/xml");
+
+ // nsConsoleService notifies its listeners via async proxies, so we need
+ // to wait to see whether there was an error reported.
+ setTimeout(step2, 0);
+
+
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug430050.xhtml b/dom/base/test/chrome/test_bug430050.xhtml
new file mode 100644
index 0000000000..f6f005fae2
--- /dev/null
+++ b/dom/base/test/chrome/test_bug430050.xhtml
@@ -0,0 +1,50 @@
+<?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=430050
+-->
+<window title="Mozilla Bug 430050"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=430050"
+ target="_blank">Mozilla Bug 430050</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 430050 **/
+
+ function endTest() {
+ ok(document.getElementById('b').contentDocument.documentElement.textContent ==
+ "succeeded", "Wrong URL loaded!");
+ SimpleTest.finish();
+ }
+
+ function startTest() {
+ document.documentElement.addEventListener('DOMAttrModified',
+ function(evt) {
+ if (evt.target == evt.currentTarget) {
+ document.getElementById('b').setAttribute("src",
+ "data:text/plain,failed");
+ const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
+ document.getElementById('b').loadURI(Services.io.newURI('data:text/plain,succeeded'), {
+ triggeringPrincipal: systemPrincipal
+ });
+ document.getElementById('b').addEventListener("load", endTest);
+ }
+ }, true);
+ document.documentElement.setAttribute("foo", "bar");
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(startTest);
+
+ ]]></script>
+ <browser flex="1" id="b"/>
+</window>
diff --git a/dom/base/test/chrome/test_bug467123.xhtml b/dom/base/test/chrome/test_bug467123.xhtml
new file mode 100644
index 0000000000..222883badf
--- /dev/null
+++ b/dom/base/test/chrome/test_bug467123.xhtml
@@ -0,0 +1,44 @@
+<?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=467123
+-->
+<window title="Mozilla Bug 467123"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=467123"
+ target="_blank">Mozilla Bug 467123</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ /** Test for Bug 467123 **/
+ let url = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService)
+ .newURI(document.location.href);
+ let file = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIChromeRegistry)
+ .convertChromeURL(url)
+ .QueryInterface(Ci.nsIFileURL)
+ .file.parent;
+ file.append("clonedoc");
+ Components.manager.addBootstrappedManifestLocation(file);
+
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "chrome://clonedoc/content/doc.xml", false);
+ xhr.send();
+ ok(xhr.responseXML, "We should have response document!");
+ var e = null;
+ try {
+ var clone = xhr.responseXML.cloneNode(true);
+ } catch (ex) {
+ e = ex;
+ }
+ ok(!e, e);
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug473284.xhtml b/dom/base/test/chrome/test_bug473284.xhtml
new file mode 100644
index 0000000000..87c778a615
--- /dev/null
+++ b/dom/base/test/chrome/test_bug473284.xhtml
@@ -0,0 +1,83 @@
+<?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=473284
+-->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+onload="
+var result = '';
+try {
+ document.commandDispatcher.advanceFocusIntoSubtree({});
+ result += '1';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.advanceFocusIntoSubtree(document.documentElement);
+ result += '2';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.advanceFocusIntoSubtree(null);
+ result += '3';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.focusedElement = {};
+ result += '4';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.focusedElement = document.documentElement;
+ result += '5';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.focusedElement = null;
+ result += '6';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.focusedWindow = {};
+ result += 'a';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.focusedWindow = null;
+ result += 'b';
+} catch (ex) {
+ result += '.';
+}
+
+try {
+ document.commandDispatcher.focusedWindow = window;
+ result += 'c';
+} catch (ex) {
+ result += '.';
+}
+
+is(result, '.23.56.bc', 'The correct assignments throw.');
+">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=473284"
+ target="_blank">Mozilla Bug 473284</a>
+ </body>
+</window>
diff --git a/dom/base/test/chrome/test_bug549682.xhtml b/dom/base/test/chrome/test_bug549682.xhtml
new file mode 100644
index 0000000000..0f1ecf646a
--- /dev/null
+++ b/dom/base/test/chrome/test_bug549682.xhtml
@@ -0,0 +1,32 @@
+<?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=549682
+-->
+<window title="Mozilla Bug 549682"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=549682"
+ target="_blank">Mozilla Bug 549682</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 549682 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function done() {
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(function() {
+ window.openDialog("file_bug549682.xhtml", "", "chrome,noopener", window);
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug571390.xhtml b/dom/base/test/chrome/test_bug571390.xhtml
new file mode 100644
index 0000000000..ea1f357a5d
--- /dev/null
+++ b/dom/base/test/chrome/test_bug571390.xhtml
@@ -0,0 +1,42 @@
+<?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=571390
+-->
+<window title="Mozilla Bug 571390"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ class="foo bar">
+ <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=571390"
+ target="_blank">Mozilla Bug 571390</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 571390 **/
+
+ is(document.documentElement.classList.length, 2, "Should have 2 classes.");
+ ok(document.documentElement.classList.contains("foo"), "Should contain 'foo' class.");
+ ok(document.documentElement.classList.contains("bar"), "Should contain 'bar' class.");
+ ok(!document.documentElement.classList.contains("foobar"), "Shouldn't contain 'foobar' class.");
+
+ document.documentElement.classList.add("foobar");
+ is(document.documentElement.classList.length, 3, "Should have 3 classes.");
+ ok(document.documentElement.classList.contains("foo"), "Should contain 'foo' class.");
+ ok(document.documentElement.classList.contains("bar"), "Should contain 'bar' class.");
+ ok(document.documentElement.classList.contains("foobar"), "Should contain 'foobar' class.");
+
+ document.documentElement.classList.remove("foobar");
+ is(document.documentElement.classList.length, 2, "Should have 2 classes.");
+ ok(document.documentElement.classList.contains("foo"), "Should contain 'foo' class.");
+ ok(document.documentElement.classList.contains("bar"), "Should contain 'bar' class.");
+ ok(!document.documentElement.classList.contains("foobar"), "Shouldn't contain 'foobar' class.");
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug616841.xhtml b/dom/base/test/chrome/test_bug616841.xhtml
new file mode 100644
index 0000000000..f5907f0b0b
--- /dev/null
+++ b/dom/base/test/chrome/test_bug616841.xhtml
@@ -0,0 +1,30 @@
+<?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=616841
+-->
+<window title="Mozilla Bug 616841"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=616841"
+ target="_blank">Mozilla Bug 616841</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ function done() {
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(function() {
+ window.openDialog("file_bug616841.xhtml", "", "chrome,noopener", window);
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug635835.xhtml b/dom/base/test/chrome/test_bug635835.xhtml
new file mode 100644
index 0000000000..69bb3ae68b
--- /dev/null
+++ b/dom/base/test/chrome/test_bug635835.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=635835
+-->
+<window title="Mozilla Bug 635835"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=635835"
+ target="_blank">Mozilla Bug 635835</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+SimpleTest.waitForExplicitFinish();
+const SHOW_ALL = NodeFilter.SHOW_ALL;
+
+addLoadEvent(function() {
+ var walker = document.createTreeWalker(document, SHOW_ALL, null);
+ try {
+ walker.currentNode = {};
+ walker.nextNode();
+ }
+ catch (e) {
+ // do nothing - this is a crash test
+ }
+ ok(true, "Crash test passed");
+ SimpleTest.finish();
+});
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug682305.html b/dom/base/test/chrome/test_bug682305.html
new file mode 100644
index 0000000000..d500dc91d5
--- /dev/null
+++ b/dom/base/test/chrome/test_bug682305.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=682305
+-->
+<head>
+ <title>XMLHttpRequest send and channel implemented in JS</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" 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=682305">Mozilla Bug 682305</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+/*
+ * Register a custom nsIProtocolHandler service
+ * in order to be able to implement *and use* an
+ * nsIChannel component written in Javascript.
+ */
+
+const { ComponentUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/ComponentUtils.sys.mjs"
+);
+
+var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
+ .getService(Ci.nsIContentSecurityManager);
+
+var PROTOCOL_SCHEME = "jsproto";
+
+
+function CustomChannel(uri, loadInfo) {
+ this.URI = this.originalURI = uri;
+ this.loadInfo = loadInfo;
+}
+CustomChannel.prototype = {
+ URI: null,
+ originalURI: null,
+ loadInfo: null,
+ contentCharset: "utf-8",
+ contentLength: 0,
+ contentType: "text/plain",
+ owner: Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
+ securityInfo: null,
+ notificationCallbacks: null,
+ loadFlags: 0,
+ loadGroup: null,
+ name: null,
+ status: Cr.NS_OK,
+ asyncOpen(listener) {
+ // throws an error if security checks fail
+ var outListener = contentSecManager.performSecurityCheck(this, listener);
+ let stream = this.open();
+ try {
+ outListener.onStartRequest(this);
+ } catch (e) {}
+ try {
+ outListener.onDataAvailable(this, stream, 0, stream.available());
+ } catch (e) {}
+ try {
+ outListener.onStopRequest(this, Cr.NS_OK);
+ } catch (e) {}
+ },
+ open() {
+ // throws an error if security checks fail
+ contentSecManager.performSecurityCheck(this, null);
+
+ let data = "bar";
+ let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
+ stream.setData(data, data.length);
+ return stream;
+ },
+ isPending() {
+ return false;
+ },
+ cancel() {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ },
+ suspend() {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ },
+ resume() {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ },
+ QueryInterface: ChromeUtils.generateQI(["nsIChannel", "nsIRequest"]),
+};
+
+
+function CustomProtocol() {}
+CustomProtocol.prototype = {
+ get scheme() {
+ return PROTOCOL_SCHEME;
+ },
+ allowPort: function allowPort() {
+ return false;
+ },
+ newChannel: function newChannel(URI, loadInfo) {
+ return new CustomChannel(URI, loadInfo);
+ },
+ QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference", "nsIProtocolHandler"]),
+};
+
+var gFactory = {
+ register() {
+ Services.io.registerProtocolHandler(
+ PROTOCOL_SCHEME,
+ new CustomProtocol(),
+ Ci.nsIProtocolHandler.URI_NORELATIVE |
+ Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
+ Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD,
+ -1
+ );
+
+ this.unregister = function() {
+ Services.io.unregisterProtocolHandler(PROTOCOL_SCHEME);
+ delete this.unregister;
+ };
+ },
+};
+
+// Register the custom procotol handler
+gFactory.register();
+
+// Then, checks if XHR works with it
+var xhr = new XMLHttpRequest();
+xhr.open("GET", PROTOCOL_SCHEME + ":foo", true);
+xhr.onload = function() {
+ is(xhr.responseText, "bar", "protocol doesn't work");
+ gFactory.unregister();
+ SimpleTest.finish();
+};
+try {
+ xhr.send(null);
+} catch (e) {
+ ok(false, e);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/chrome/test_bug683852.xhtml b/dom/base/test/chrome/test_bug683852.xhtml
new file mode 100644
index 0000000000..1f9e0d9472
--- /dev/null
+++ b/dom/base/test/chrome/test_bug683852.xhtml
@@ -0,0 +1,87 @@
+<?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=683852
+-->
+<window title="Mozilla Bug 683852"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:xul="http://www.mozilla.org/keymaster/gaktekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <script>
+ <![CDATA[
+ customElements.define("custom-element", class extends XULElement {
+ constructor() {
+ super();
+ const template = document.getElementById("template");
+ this.attachShadow({mode: "open"})
+ .appendChild(template.content.cloneNode(true));
+ }
+ });
+ ]]>
+ </script>
+ <html:template id="template"><xul:box anonid="anon">Anonymous</xul:box></html:template>
+ <custom-element id="custom-element"/>
+
+ <!-- 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=683852"
+ target="_blank" id="link">Mozilla Bug 683852</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 683852 **/
+ SimpleTest.waitForExplicitFinish();
+
+ const NS_HTML = "http://www.w3.org/1999/xhtml";
+
+ function startTest() {
+ is(document.contains(document), true, "Document should contain itself!");
+
+ let box = document.getElementById("custom-element");
+ is(document.contains(box), true, "Document should contain element in it!");
+ is(box.contains(box), true, "Element should contain itself.")
+ let anon = box.shadowRoot.querySelector("[anonid=anon]");
+ is(document.contains(anon), false, "Document should not contain anonymous element in it!");
+ is(box.contains(anon), false, "Element should not contain anonymous element in it!");
+ is(anon.contains(anon), true, "Anonymous element should contain itself.")
+ is(document.documentElement.contains(box), true, "Element should contain element in it!");
+ is(document.contains(document.createXULElement("foo")), false, "Document shouldn't contain element which is't in the document");
+ is(document.contains(document.createTextNode("foo")), false, "Document shouldn't contain text node which is't in the document");
+
+ var link = document.getElementById("link");
+ is(document.contains(link.firstChild), true,
+ "Document should contain a text node in it.");
+ is(link.contains(link.firstChild), true,
+ "Element should contain a text node in it.");
+ is(link.firstChild.contains(link), false, "text node shouldn't contain its parent.");
+
+ is(document.contains(null), false, "Document shouldn't contain null.");
+
+ var pi = document.createProcessingInstruction("adf", "asd");
+ is(pi.contains(document), false, "Processing instruction shouldn't contain document");
+ document.documentElement.appendChild(pi);
+ document.contains(pi, true, "Document should contain processing instruction");
+
+ var df = document.createRange().createContextualFragment(`<div xmlns="${NS_HTML}">foo</div>`);
+ is(df.contains(df.firstChild), true, "Document fragment should contain its child");
+ is(df.contains(df.firstChild.firstChild), true,
+ "Document fragment should contain its descendant");
+ is(df.contains(df), true, "Document fragment should contain itself.");
+
+ var d = document.implementation.createHTMLDocument("");
+ is(document.contains(d), false,
+ "Document shouldn't contain another document.");
+ is(document.contains(d.createElement("div")), false,
+ "Document shouldn't contain an element from another document.");
+
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(startTest);
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug752226-3.xhtml b/dom/base/test/chrome/test_bug752226-3.xhtml
new file mode 100644
index 0000000000..747fb29c4e
--- /dev/null
+++ b/dom/base/test/chrome/test_bug752226-3.xhtml
@@ -0,0 +1,28 @@
+<?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=752226
+-->
+<window title="Mozilla Bug 752226"
+ 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=752226"
+ target="_blank">Mozilla Bug 752226</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 752226 **/
+ try {
+ new File(null);
+ } catch (e) {}
+ ok(true, "Didn't crash");
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug752226-4.xhtml b/dom/base/test/chrome/test_bug752226-4.xhtml
new file mode 100644
index 0000000000..242e231a2e
--- /dev/null
+++ b/dom/base/test/chrome/test_bug752226-4.xhtml
@@ -0,0 +1,28 @@
+<?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=752226
+-->
+<window title="Mozilla Bug 752226"
+ 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=752226"
+ target="_blank">Mozilla Bug 752226</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 752226 **/
+ try {
+ new Cu.Sandbox("about:blank", null);
+ } catch (e) {}
+ ok(true, "Didn't crash");
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug765993.html b/dom/base/test/chrome/test_bug765993.html
new file mode 100644
index 0000000000..3325c3713d
--- /dev/null
+++ b/dom/base/test/chrome/test_bug765993.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=765993
+-->
+<head>
+ <title>Test for Bug 765993</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" 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=765993">Mozilla Bug 765993</a>
+<style type="text/css">
+#link1 a { user-select:none; }
+</style>
+<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
+<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 765993 **/
+
+const {addDebuggerToGlobal} = ChromeUtils.importESModule("resource://gre/modules/jsdebugger.sys.mjs");
+addDebuggerToGlobal(globalThis);
+
+window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ var iframe = document.createElement("iframe");
+ iframe.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug765993.html";
+ iframe.onload = function() {
+ var script = iframe.contentWindow.document.createElement("script");
+ script.src = "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug765993.js";
+ script.onload = function() {
+ var dbg = new Debugger(iframe.contentWindow);
+ ok(dbg, "Should be able to create debugger");
+
+ var scripts = dbg.findScripts({
+ url: "http://mochi.test:8888/tests/dom/base/test/chrome/nochrome_bug765993.js",
+ });
+ ok(scripts.length, "Should be able to find script");
+
+ is(scripts[0].source.sourceMapURL, "foo.js.map");
+ SimpleTest.finish();
+ };
+
+ iframe.contentWindow.document.body.appendChild(script);
+ };
+
+ document.body.appendChild(iframe);
+};
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/chrome/test_bug780199.xhtml b/dom/base/test/chrome/test_bug780199.xhtml
new file mode 100644
index 0000000000..e27afb72fa
--- /dev/null
+++ b/dom/base/test/chrome/test_bug780199.xhtml
@@ -0,0 +1,51 @@
+<?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=780199
+-->
+<window title="Mozilla Bug 780199"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="test()">
+ <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=780199"
+ target="_blank">Mozilla Bug 780199</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 780199 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ var b;
+
+ function callback(r) {
+ is(r[0].type, "attributes");
+ is(r[0].oldValue, b.getAttribute("src"));
+ setTimeout(continueTest, 500);
+ }
+
+ function continueTest() {
+ // Check that a new page wasn't loaded.
+ is(b.contentDocument.documentElement.textContent, "testvalue");
+ SimpleTest.finish();
+ }
+
+ function test() {
+ b = document.getElementById("b");
+ var m = new MutationObserver(callback);
+ m.observe(b, { attributes: true, attributeOldValue: true });
+ b.contentDocument.documentElement.textContent = "testvalue";
+ b.setAttribute("src", b.getAttribute("src"));
+ }
+
+ ]]>
+ </script>
+ <browser id="b" src="data:text/plain,initial"/>
+</window>
diff --git a/dom/base/test/chrome/test_bug780529.xhtml b/dom/base/test/chrome/test_bug780529.xhtml
new file mode 100644
index 0000000000..bf8b8b2981
--- /dev/null
+++ b/dom/base/test/chrome/test_bug780529.xhtml
@@ -0,0 +1,36 @@
+<?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=780529
+-->
+<window title="Mozilla Bug 780529"
+ 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=780529"
+ target="_blank">Mozilla Bug 780529</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 780529 **/
+var req = new XMLHttpRequest();
+req.open("GET", "", true);
+// Have to call send() to get the XHR hooked up as the notification callbacks
+req.send();
+var callbacks = req.channel.notificationCallbacks;
+var sink = callbacks.getInterface(Ci.nsIChannelEventSink);
+ok(sink instanceof Ci.nsIChannelEventSink,
+ "Should be a channel event sink")
+ok("asyncOnChannelRedirect" in sink,
+ "Should have the right methods for an event sink");
+
+let sinkReq = sink.QueryInterface(Ci.nsIInterfaceRequestor);
+isnot(sinkReq, callbacks, "Sink should not be the XHR object");
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug800386.xhtml b/dom/base/test/chrome/test_bug800386.xhtml
new file mode 100644
index 0000000000..681c9a9794
--- /dev/null
+++ b/dom/base/test/chrome/test_bug800386.xhtml
@@ -0,0 +1,65 @@
+<?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=800386
+-->
+<window title="Mozilla Bug 800386"
+ 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=800386"
+ target="_blank">Mozilla Bug 800386</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 800386 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var triedForwarding = false;
+ var forwardFailed = false;
+
+ var xhr = new XMLHttpRequest;
+ var xhr2 = new XMLHttpRequest;
+
+ var eventSink = xhr.getInterface(Ci.nsIProgressEventSink);
+ isnot(eventSink, null, "Should get event sink directly!");
+
+ // Now jump through some hoops to get us a getInterface call from C++
+
+ var requestor = {
+ getInterface: function(aIID) {
+ if (aIID.equals(Ci.nsIProgressEventSink)) {
+ triedForwarding = true;
+ try {
+ return xhr2.getInterface(aIID);
+ } catch (e) {
+ forwardFailed = true;
+ }
+ }
+ throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
+ },
+
+ QueryInterface: ChromeUtils.generateQI(["nsIInterfaceRequestor"])
+ };
+
+ // HTTP URI so that we get progress callbacks
+ xhr.open("GET", "http://mochi.test:8888/", false);
+ xhr.channel.notificationCallbacks = requestor;
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ ok(triedForwarding,
+ "Should have had an attempt to treat us as a progress event sink");
+ ok(!forwardFailed,
+ "Should have been able to forward getInterface on to the XHR");
+ SimpleTest.finish();
+ }
+ }
+ xhr.send();
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_bug816340.xhtml b/dom/base/test/chrome/test_bug816340.xhtml
new file mode 100644
index 0000000000..66bd26660e
--- /dev/null
+++ b/dom/base/test/chrome/test_bug816340.xhtml
@@ -0,0 +1,30 @@
+<?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=816340
+-->
+<window title="Mozilla Bug 816340"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=816340"
+ target="_blank">Mozilla Bug 816340</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ function done() {
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(function() {
+ window.openDialog("file_bug816340.xhtml", "", "chrome,noopener", window);
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug884693.xhtml b/dom/base/test/chrome/test_bug884693.xhtml
new file mode 100644
index 0000000000..db6eca88a8
--- /dev/null
+++ b/dom/base/test/chrome/test_bug884693.xhtml
@@ -0,0 +1,82 @@
+<?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=884693
+-->
+<window title="Mozilla Bug 884693"
+ 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=884693"
+ target="_blank">Mozilla Bug 884693</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ const SERVER_URL = "http://mochi.test:8888/tests/dom/base/test/chrome/bug884693.sjs";
+ const INVALID_XML = "InvalidXML";
+ const XML_WITHOUT_ROOT = "<?xml version='1.0'?>";
+
+ let consoleService = Cc["@mozilla.org/consoleservice;1"].
+ getService(Ci.nsIConsoleService)
+
+ function runTest(status, statusText, body, expectedResponse, expectedMessages)
+ {
+ return new Promise((resolve, reject) => {
+ consoleService.reset();
+
+ let xhr = new XMLHttpRequest();
+
+ xhr.onload = () => {
+ is(xhr.responseText, expectedResponse, "Correct responseText returned");
+
+ let messages = consoleService.getMessageArray() || [];
+ // broadcastlisteners can happen and cause false alarm.
+ messages = messages.filter(msg =>
+ !(msg instanceof Ci.nsIScriptError &&
+ msg.category.includes("chrome javascript") &&
+ msg.message.includes("Unknown event")));
+
+ if (messages.length) {
+ info(`Got console messages ${messages}`);
+ }
+ is(messages.length, expectedMessages.length, "Got expected message count");
+ messages = messages.map(m => m.message).join(",");
+ for(let message of expectedMessages) {
+ ok(messages.includes(message), "Got expected message: " + message);
+ }
+
+ resolve();
+ };
+
+ xhr.onerror = e => {
+ reject(e);
+ };
+
+ xhr.open("GET", `${SERVER_URL}?${status}&${statusText}&${body}`);
+ xhr.send();
+ });
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ runTest(201, "Created", "", "", []).
+ then(() => { return runTest(201, "Created", INVALID_XML, INVALID_XML, []); }).
+ then(() => { return runTest(202, "Accepted", "", "", []); }).
+ then(() => { return runTest(202, "Accepted", INVALID_XML, INVALID_XML, []); }).
+ then(() => { return runTest(204, "No Content", "", "", []); }).
+ then(() => { return runTest(204, "No Content", INVALID_XML, "", []); }).
+ then(() => { return runTest(205, "Reset Content", "", "", []); }).
+ then(() => { return runTest(205, "Reset Content", INVALID_XML, "", []); }).
+ then(() => { return runTest(304, "Not modified", "", "", []); }).
+ then(() => { return runTest(304, "Not modified", INVALID_XML, "", []); }).
+ then(() => { return runTest(200, "OK", "", "", []); }).
+ then(() => { return runTest(200, "OK", XML_WITHOUT_ROOT, XML_WITHOUT_ROOT, ["no root element found"]); }).
+ then(() => { return runTest(200, "OK", INVALID_XML, INVALID_XML, ["syntax error"]); }).
+ then(SimpleTest.finish);
+
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_bug914381.html b/dom/base/test/chrome/test_bug914381.html
new file mode 100644
index 0000000000..eb82ffd0f7
--- /dev/null
+++ b/dom/base/test/chrome/test_bug914381.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650776
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 914381</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.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=914381">Mozilla Bug 914381</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+function createFileWithData(fileData) {
+ var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ testFile.append("testBug914381");
+
+ var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+ outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
+ 0o666, 0);
+ outStream.write(fileData, fileData.length);
+ outStream.close();
+
+ return testFile;
+}
+
+/** Test for Bug 914381. File's created in JS using an nsIFile should allow mozGetFullPathInternal calls to succeed **/
+var file = createFileWithData("Test bug 914381");
+
+SpecialPowers.pushPrefEnv({ set: [["dom.file.createInChild", true]]})
+.then(() => {
+ return File.createFromNsIFile(file);
+})
+.then(f => {
+ is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js");
+ is(f.mozFullPath, file.path, "mozFullPath returns path if created with nsIFile");
+})
+.then(() => {
+ return File.createFromFileName(file.path);
+})
+.then(f => {
+ is(f.mozFullPathInternal, undefined, "mozFullPathInternal is undefined from js");
+ is(f.mozFullPath, "", "mozFullPath returns blank if created with a string");
+})
+.then(() => {
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/chrome/test_bug990812.xhtml b/dom/base/test/chrome/test_bug990812.xhtml
new file mode 100644
index 0000000000..410d6d2367
--- /dev/null
+++ b/dom/base/test/chrome/test_bug990812.xhtml
@@ -0,0 +1,42 @@
+<?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=990812
+-->
+<window title="Mozilla Bug 990812"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=990812"
+ target="_blank">Mozilla Bug 990812</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ var tests = [
+ "file_bug990812-1.xhtml",
+ "file_bug990812-2.xhtml",
+ "file_bug990812-3.xhtml",
+ "file_bug990812-4.xhtml",
+ "file_bug990812-5.xhtml",
+ ];
+
+ function next() {
+ if (tests.length) {
+ var file = tests.shift();
+ info("-- running " + file);
+ window.openDialog(file, "_blank", "chrome,noopener", window);
+ } else {
+ SimpleTest.finish();
+ }
+ }
+
+ addLoadEvent(next);
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_chromeOuterWindowID.xhtml b/dom/base/test/chrome/test_chromeOuterWindowID.xhtml
new file mode 100644
index 0000000000..880cfdf8bb
--- /dev/null
+++ b/dom/base/test/chrome/test_chromeOuterWindowID.xhtml
@@ -0,0 +1,137 @@
+<?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=1474662
+Test that the chromeOuterWindowID on the MessageManager interface
+works, and that it properly updates when swapping frameloaders between
+windows.
+-->
+<window title="Mozilla Bug 1474662"
+ 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=1474662"
+ target="_blank">Mozilla Bug 1474662</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+ const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
+ const {ContentTask} = ChromeUtils.import("resource://testing-common/ContentTask.jsm");
+
+ const BROWSER_DOC = "window_chromeOuterWindowID.xhtml";
+ const TEST_PAGE = "http://example.com";
+ const TEST_PAGE_2 = "http://example.com/browser";
+
+ function getOuterWindowID(win) {
+ return win.docShell.outerWindowID;
+ }
+
+ /**
+ * Takes two <xul:browser>'s that should be in the same document, and
+ * ensures that their frame script environments know the correct value
+ * of the host window's outerWindowID.
+ */
+ async function ensureExpectedChromeOuterWindowIDs(browser1, browser2) {
+ is(browser1.ownerDocument, browser2.ownerDocument,
+ "Both browsers should belong to the same document.");
+ let winID = getOuterWindowID(browser1.ownerGlobal);
+
+ let getChildRootOuterId = browser => {
+ try {
+ return docShell.browserChild?.chromeOuterWindowID;
+ } catch(ex) { }
+
+ // Not a remote tab
+ return content.top.windowRoot.ownerGlobal.docShell.outerWindowID;
+ };
+
+ let browser1ID = await SpecialPowers.spawn(browser1, [], getChildRootOuterId);
+ let browser2ID = await SpecialPowers.spawn(browser2, [], getChildRootOuterId);
+
+ is(browser1ID, winID,
+ "Browser 1 frame script environment should have the correct chromeOuterWindowID");
+ is(browser2ID, winID,
+ "Browser 1 frame script environment should have the correct chromeOuterWindowID");
+ }
+
+ /**
+ * Opens up a BROWSER_DOC test window, and points each browser to a particular
+ * page.
+ *
+ * @param num (Number)
+ * An identifier number for this window. Mainly used as a suffix for the
+ * returned values.
+ * @param page (String)
+ * A URL to load in each <xul:browser>
+ * @returns Promise
+ * The Promise resolves with an object with the following properties:
+ *
+ * win<num>: a reference to the opened window
+ * remote<num>: a reference to the remote browser in the window
+ * nonRemote<num>: a reference to the non-remote browser in the window
+ */
+ async function prepareWindow(num, page) {
+ let win = window.browsingContext.topChromeWindow.open(BROWSER_DOC, "bug1474662-" + num, "chrome,width=200,height=200");
+ await BrowserTestUtils.waitForEvent(win, "load");
+ let remote = win.document.getElementById("remote");
+ let nonRemote = win.document.getElementById("non-remote");
+
+ ok(remote && remote.isRemoteBrowser,
+ "Should have found a remote browser in test window " + num);
+ ok(nonRemote && !nonRemote.isRemoteBrowser,
+ "Should have found a non-remote browser in test window " + num);
+
+ BrowserTestUtils.loadURIString(remote, page);
+ await BrowserTestUtils.browserLoaded(remote);
+ BrowserTestUtils.loadURIString(nonRemote, page);
+ await BrowserTestUtils.browserLoaded(nonRemote);
+
+ let result = {};
+ result["win" + num] = win;
+ result["remote" + num] = remote;
+ result["nonRemote" + num] = nonRemote;
+ return result;
+ }
+
+ add_task(async () => {
+ let { win1, remote1, nonRemote1 } = await prepareWindow(1, TEST_PAGE);
+ let { win2, remote2, nonRemote2 } = await prepareWindow(2, TEST_PAGE_2);
+
+ let win1ID = getOuterWindowID(win1);
+ let win2ID = getOuterWindowID(win2);
+
+ // Quick sanity-test here - if something has gone horribly wrong
+ // and the windows have the same IDs, then the rest of this test
+ // is meaningless.
+ isnot(win1ID, win2ID,
+ "The windows should definitely have different IDs.");
+
+ await ensureExpectedChromeOuterWindowIDs(remote1, nonRemote1);
+ await ensureExpectedChromeOuterWindowIDs(remote2, nonRemote2);
+
+ // Swap the frameloaders! This doesn't swap the <browser> elements though,
+ // so what's expected is that the IDs should remain the same within
+ // the browsers despite the underlying content changing.
+ remote1.swapFrameLoaders(remote2);
+ nonRemote1.swapFrameLoaders(nonRemote2);
+
+ await ensureExpectedChromeOuterWindowIDs(remote1, nonRemote1);
+ await ensureExpectedChromeOuterWindowIDs(remote2, nonRemote2);
+
+ // Now swap them back.
+ remote1.swapFrameLoaders(remote2);
+ nonRemote1.swapFrameLoaders(nonRemote2);
+
+ await ensureExpectedChromeOuterWindowIDs(remote1, nonRemote1);
+ await ensureExpectedChromeOuterWindowIDs(remote2, nonRemote2);
+
+ await BrowserTestUtils.closeWindow(win1);
+ await BrowserTestUtils.closeWindow(win2);
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_custom_element_content.xhtml b/dom/base/test/chrome/test_custom_element_content.xhtml
new file mode 100644
index 0000000000..7778bc350e
--- /dev/null
+++ b/dom/base/test/chrome/test_custom_element_content.xhtml
@@ -0,0 +1,55 @@
+<?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=1130028
+-->
+<window title="Mozilla Bug 1130028"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=1130028"
+ target="_blank">Mozilla Bug 1130028</a>
+ <iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_custom_element_content.html"></iframe>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 1130028 **/
+ var connectedCallbackCount = 0;
+
+ function startTests() {
+ var frame = $("frame");
+
+ class XFoo extends frame.contentWindow.HTMLElement {};
+ frame.contentWindow.customElements.define("x-foo", XFoo);
+ var elem = new XFoo();
+ is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
+
+ class XBar extends frame.contentWindow.HTMLElement {
+ constructor() {
+ super();
+ this.magicNumber = 42;
+ }
+
+ connectedCallback() {
+ connectedCallbackCount++;
+ // Callback should be called only once by element created in content.
+ is(connectedCallbackCount, 1, "Connected callback called, should be called once in test.");
+ is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
+ }
+ };
+
+ frame.contentWindow.customElements.define("x-bar", XBar);
+ is(connectedCallbackCount, 1, "Connected callback should be called by element created in content.");
+
+ var element = frame.contentDocument.createElement("x-bar");
+ is(element.magicNumber, 42, "Should be able to see the custom prototype on created element.");
+ }
+
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_custom_element_ep.xhtml b/dom/base/test/chrome/test_custom_element_ep.xhtml
new file mode 100644
index 0000000000..28b4e876f5
--- /dev/null
+++ b/dom/base/test/chrome/test_custom_element_ep.xhtml
@@ -0,0 +1,41 @@
+<?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=1130028
+-->
+<window title="Mozilla Bug 1130028"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=1130028"
+ target="_blank">Mozilla Bug 1130028</a>
+ <iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_custom_element_content.html"></iframe>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+
+ /** Test for Bug 1130028 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function finishTest(canSeePrototype) {
+ ok(true, "connectedCallback called when reigsterElement was called with an extended principal.");
+ ok(canSeePrototype, "connectedCallback should be able to see custom prototype.");
+ SimpleTest.finish();
+ }
+
+ function startTests() {
+ var frame = $("frame");
+
+ // Create a sandbox with an extended principal then run a script that registers a custom element in the sandbox.
+ var sandbox = Cu.Sandbox([frame.contentWindow], { sandboxPrototype: frame.contentWindow });
+ sandbox.finishTest = finishTest;
+ Services.scriptloader.loadSubScript("chrome://mochitests/content/chrome/dom/base/test/chrome/custom_element_ep.js", sandbox);
+ }
+
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_document-element-inserted.xhtml b/dom/base/test/chrome/test_document-element-inserted.xhtml
new file mode 100644
index 0000000000..5fd35e364d
--- /dev/null
+++ b/dom/base/test/chrome/test_document-element-inserted.xhtml
@@ -0,0 +1,54 @@
+<?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=1411707
+-->
+<window title="Mozilla Bug 1411707"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=1411707"
+ target="_blank">Mozilla Bug 1411707</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ const OUTER_URL = "chrome://mochitests/content/chrome/dom/base/test/chrome/file_document-element-inserted.xhtml";
+ const INNER_URL = "chrome://mochitests/content/chrome/dom/base/test/chrome/file_document-element-inserted-inner.xhtml";
+
+ async function waitForEvent(url) {
+ return new Promise(resolve => {
+ SpecialPowers.addObserver(function inserted(document) {
+ is(document.documentURI, url, "Correct URL");
+ is(document.readyState, "loading", "Correct readyState");
+ SpecialPowers.removeObserver(inserted, "document-element-inserted");
+ resolve();
+ }, "document-element-inserted");
+ })
+ }
+
+ // Load a XUL document that also has an iframe to a subdocument, and
+ // expect both events to fire with the docs in the correct state.
+ async function testEvents() {
+ info(`Waiting for events after loading ${OUTER_URL}`);
+ let win = window.browsingContext.topChromeWindow.openDialog(OUTER_URL, "_blank", "chrome,dialog=no,all");
+ await waitForEvent(OUTER_URL);
+ await waitForEvent(INNER_URL);
+ win.close();
+ }
+
+ (async function() {
+ // Test the same document twice to make to make sure we are
+ // firing properly when loading the protype document.
+ await testEvents();
+ await testEvents();
+ SimpleTest.finish();
+ })();
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_domparsing.xhtml b/dom/base/test/chrome/test_domparsing.xhtml
new file mode 100644
index 0000000000..be04bdfc0d
--- /dev/null
+++ b/dom/base/test/chrome/test_domparsing.xhtml
@@ -0,0 +1,145 @@
+<?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"?>
+<window title="Test for the Mozilla extesion of the DOM Parsing and Serialization API"
+ 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"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=816410"
+ target="_blank">Mozilla Bug 816410</a>
+ <xul:browser id="test1" type="content" src="data:text/html,content" />
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+"use strict";
+/** Test for Bug 816410 **/
+
+function throws(fn, type, message) {
+ try {
+ fn();
+ ok(false, message);
+ } catch (e) {
+ if (type) {
+ is(e.name, type, message);
+ } else {
+ ok(true, message);
+ }
+ }
+}
+
+add_task(function dom_parser_extra_args() {
+ // DOMParser constructor should not throw for extra arguments
+ new DOMParser(undefined);
+ new DOMParser(null);
+ new DOMParser(false);
+ new DOMParser(0);
+ new DOMParser("");
+ new DOMParser({});
+});
+
+add_task(function xml_serializer_extra_args() {
+ // XMLSerializer constructor should not throw for extra arguments
+ new XMLSerializer(undefined);
+ new XMLSerializer(null);
+ new XMLSerializer(false);
+ new XMLSerializer(0);
+ new XMLSerializer("");
+ new XMLSerializer({});
+});
+
+add_task(function chrome_window() {
+ runTest(window, true);
+});
+
+add_task(function content_window() {
+ runTest(document.getElementById("test1").contentWindow, false);
+});
+
+function runTest(win, expectSystem) {
+ let parser = new win.DOMParser();
+ let serializer = new win.XMLSerializer();
+ let principal = win.document.nodePrincipal;
+ is(principal.isSystemPrincipal, expectSystem,
+ `expected ${expectSystem ? "system" : "content"} principal`);
+
+ is(typeof parser.parseFromString, "function", "parseFromString should exist");
+ is(typeof parser.parseFromBuffer, "function", "parseFromBuffer should exist");
+ is(typeof parser.parseFromStream, "function", "parseFromStream should exist");
+ is(typeof parser.parseFromSafeString, "function", "parseFromSafeString should exist");
+
+ is(typeof serializer.serializeToString, "function", "serializeToString should exist");
+ is(typeof serializer.serializeToStream, "function", "serializeToStream should exist");
+
+ let tests = [
+ {input: "<html></html>", type: "text/html",
+ expected: '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body></body></html>'},
+ {input: "<xml></xml>", type: "text/xml", expected: "<xml/>"},
+ {input: "<xml></xml>", type: "application/xml", expected: "<xml/>"},
+ {input: "<html></html>", type: "application/xhtml+xml", expected: "<html/>"},
+ {input: "<svg></svg>", type: "image/svg+xml", expected: "<svg/>"},
+ ];
+ for (let t of tests) {
+ const fromNormalString = parser.parseFromString(t.input, t.type);
+ if (principal.isSystemPrincipal) {
+ ok(fromNormalString.nodePrincipal.isNullPrincipal,
+ "system principal DOMParser produces a null principal document");
+ } else {
+ ok(fromNormalString.nodePrincipal === principal,
+ "content principal DOMParser produces a document with an object-identical principal");
+ }
+
+ const fromSafeString = parser.parseFromSafeString(t.input, t.type);
+ ok(fromSafeString.nodePrincipal === principal,
+ "DOMParser with parseFromSafeString always produces a document with an object-identical principal");
+
+ is(serializer.serializeToString(parser.parseFromString(t.input, t.type)), t.expected,
+ "parseFromString test for " + t.type);
+
+ for (let charset of [null, "UTF-8"]) {
+ let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
+ pipe.init(false, false, 0, 0xffffffff, null);
+ let ostream = pipe.outputStream;
+ serializer.serializeToStream(parser.parseFromString(t.input, t.type), ostream, charset);
+ let istream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ istream.init(pipe.inputStream);
+ let data = istream.read(0xffffffff);
+ is(data, t.expected,
+ "serializeToStream test for " + t.type + ", charset=" + charset);
+ }
+
+ if (t.type === "text/html") {
+ // parseFromBuffer and parseFromStream don't support "text/html".
+ continue;
+ }
+
+ let array = Array.from(t.input, function(c) { return c.charCodeAt(c); });
+ let inputs = [
+ {array: array, name: "parseFromBuffer (array)"},
+ {array: new Uint8Array(array), name: "parseFromBuffer (Uint8Array)"},
+ ];
+ for (let input of inputs) {
+ let a = input.array;
+ is(serializer.serializeToString(parser.parseFromBuffer(a, t.type)), t.expected,
+ input.name + " test for " + t.type);
+ }
+
+ let istream = Cc["@mozilla.org/io/string-input-stream;1"].
+ createInstance(Ci.nsIStringInputStream);
+ for (let charset of [null, "UTF-8"]) {
+ istream.setData(t.input, -1);
+ is(serializer.serializeToString(parser.parseFromStream(istream, charset, t.input.length, t.type)),
+ t.expected, "parseFromStream test for " + t.type + ", charset=" + charset);
+ }
+ }
+ throws(function() {
+ parser.parseFromString("<xml></xml>", "foo/bar");
+ }, "TypeError", "parseFromString should throw for the unknown type");
+}
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_fileconstructor.xhtml b/dom/base/test/chrome/test_fileconstructor.xhtml
new file mode 100644
index 0000000000..8884eb169b
--- /dev/null
+++ b/dom/base/test/chrome/test_fileconstructor.xhtml
@@ -0,0 +1,86 @@
+<?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=607114.xul
+-->
+<window title="Mozilla Bug 607114"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ 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=607114">
+ Mozilla Bug 607114</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 607114 **/
+
+// eslint-disable-next-line mozilla/no-addtask-setup
+add_task(async function setup() {
+ await SpecialPowers.pushPrefEnv({ set: [[ "dom.file.createInChild", true ]]});
+});
+
+add_task(async function test() {
+ var file = SpecialPowers.Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+ // man I wish this were simpler ...
+ file.append("chrome");
+ file.append("dom");
+ file.append("base");
+ file.append("test");
+ file.append("chrome");
+ file.append("fileconstructor_file.png");
+
+ let domFile = await File.createFromFileName(file.path);
+
+ ok(File.isInstance(domFile), "File() should return a File");
+ is(domFile.type, "image/png", "File should be a PNG");
+ is(domFile.size, 95, "File has size 95 (and more importantly we can read it)");
+
+ domFile = await File.createFromNsIFile(file);
+ ok(File.isInstance(domFile), "File() should return a File for an nsIFile");
+ is(domFile.type, "image/png", "File should be a PNG");
+ is(domFile.size, 95, "File has size 95 (and more importantly we can read it)");
+
+ try {
+ await File.createFromFileName(
+ "i/sure/hope/this/does/not/exist/anywhere.txt"
+ );
+ ok(false, "Attempt to construct a non-existent file should fail.");
+ } catch (ex) {
+ is(
+ ex.result,
+ Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH,
+ "Constructing a non-existing file should fail with the correct error code"
+ );
+ }
+ let dir = SpecialPowers.Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+ try {
+ await File.createFromNsIFile(dir);
+ ok(false, "Attempt to construct a file from a directory should fail.");
+ } catch (ex) {
+ is(
+ ex.result,
+ Cr.NS_ERROR_FILE_IS_DIRECTORY,
+ "Constructing a file from a directory should fail with the correct error code"
+ );
+ }
+})
+]]>
+</script>
+
+</window>
diff --git a/dom/base/test/chrome/test_getElementsWithGrid.html b/dom/base/test/chrome/test_getElementsWithGrid.html
new file mode 100644
index 0000000000..3554acb2e9
--- /dev/null
+++ b/dom/base/test/chrome/test_getElementsWithGrid.html
@@ -0,0 +1,121 @@
+<!doctype html>
+<html id="root" class="g">
+<head>
+<meta charset="utf-8">
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+.no-match {
+ display: block;
+}
+.g {
+ display: grid;
+}
+.s {
+ display: subgrid;
+}
+.gi {
+ display: inline-grid;
+}
+</style>
+
+<script>
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function testTargetsAreInElements(targets, elements) {
+ let c = 0;
+ for (let target of targets) {
+ if (c >= elements.length) {
+ ok(false, "We shouldn't have more targets than elements found.");
+ break;
+ }
+ let element = elements[c];
+ let isMatching = (target.id == element.id);
+ let test_function = (target.todo ? todo : ok);
+
+ test_function(isMatching, "Should find " + target.message + ".");
+
+ // Only move to the next element in the elements if this one was a match.
+ // This handles the case of an unexpected element showing up, and prevents
+ // cascading errors in that case. If we've instead screwed up the target
+ // list, then we will get cascading errors.
+ if (isMatching) {
+ ++c;
+ }
+ }
+
+ // Make sure we don't have any extra elements after going through all the targets.
+ is(c, elements.length, "We shouldn't have more elements than we have targets.");
+}
+
+function runTests() {
+ // Part 1: Look for all the grid elements starting from the document root.
+ let elementsFromRoot = document.documentElement.getElementsWithGrid();
+
+ // Check that the expected elements were returned.
+ // Targets are provided in order we expect them to appear.
+ // Has to end in a non-todo element in order for testing logic to work.
+ let targetsFromRoot = [
+ {id: "root", message: "root with display:grid"},
+ {id: "a", message: "'plain' grid container with display:grid"},
+ {id: "b", message: "display:subgrid inside display:grid (to be fixed in Bug 1240834)", todo: true},
+ {id: "c", message: "'plain' grid container with display:inline-grid"},
+ {id: "d", message: "display:subgrid inside display:inline-grid (to be fixed in Bug 1240834)", todo: true},
+ {id: "e", message: "grid container with visibility:hidden"},
+ {id: "f", message: "grid container inside an element"},
+ {id: "g", message: "overflow:scroll grid container"},
+ {id: "h", message: "button as a grid container"},
+ {id: "i", message: "fieldset as a grid container"},
+ {id: "k1", message: "grid container containing a grid container"},
+ {id: "k2", message: "grid container inside a grid container"},
+ ];
+ is(elementsFromRoot.length, 10, "Found expected number of elements within document root.");
+ testTargetsAreInElements(targetsFromRoot, elementsFromRoot);
+
+
+ // Part 2: Look for all the grid elements starting from a non-root element.
+ let elementsFromNonRoot = document.getElementById("a_non_root_element").getElementsWithGrid();
+
+ let targetsFromNonRoot = [
+ {id: "f", message: "grid container inside an element (from non-root element)"},
+ ];
+ is(elementsFromNonRoot.length, 1, "Found expected number of elements from non-root element.");
+ testTargetsAreInElements(targetsFromNonRoot, elementsFromNonRoot);
+
+ SimpleTest.finish();
+}
+</script>
+</head>
+<body onLoad="runTests();">
+
+<div id="a" class="g">
+ <div class="no-match"></div>
+ <div id="b" class="s"></div>
+</div>
+
+<div class="no-match"></div>
+
+<div id="c" class="gi">
+ <div id="d" class="s"></div>
+</div>
+
+<div id="e" class="g" style="visibility:hidden"></div>
+
+<div id="a_non_root_element"><div id="f" class="g"></div></div>
+
+<div class="no-match"></div>
+
+<div id="g" style="overflow:scroll" class="g"></div>
+
+<button id="h" class="g"></button>
+
+<fieldset id="i" class="g"></fieldset>
+
+<div id="a_display_none_element" style="display:none"><div id="j" class="g"></div></div>
+
+<div id="k1" class="g"><div id="k2" class="g"></div></div>
+
+</body>
+</html>
diff --git a/dom/base/test/chrome/test_input_value_set_preserve_undo.xhtml b/dom/base/test/chrome/test_input_value_set_preserve_undo.xhtml
new file mode 100644
index 0000000000..80465202ab
--- /dev/null
+++ b/dom/base/test/chrome/test_input_value_set_preserve_undo.xhtml
@@ -0,0 +1,37 @@
+<?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"?>
+<window title="Bug 1676785"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:xul="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>
+<html:body>
+ <xul:hbox>
+ <html:input id="xul" />
+ </xul:hbox>
+ <html:div>
+ <html:input id="non-xul" />
+ </html:div>
+</html:body>
+<script class="testbody">
+SimpleTest.waitForExplicitFinish();
+
+function shouldPreserveHistory(input, preserve) {
+ input.focus();
+ input.value = "abc";
+ input.value = "def";
+ let ctrl = navigator.platform.indexOf("Mac") == 0 ? { metaKey: true } : { ctrlKey: true };
+ synthesizeKey("z", ctrl);
+ (preserve ? is : isnot)(input.value, "abc", `Expected ${input.id} to ${preserve ? "" : "not "}preserve undo history when setting .value`);
+}
+
+window.onload = function() {
+ shouldPreserveHistory(document.getElementById("xul"), true);
+ shouldPreserveHistory(document.getElementById("non-xul"), false);
+
+ SimpleTest.finish();
+}
+</script>
+</window>
diff --git a/dom/base/test/chrome/test_nsITextInputProcessor.xhtml b/dom/base/test/chrome/test_nsITextInputProcessor.xhtml
new file mode 100644
index 0000000000..3343c28560
--- /dev/null
+++ b/dom/base/test/chrome/test_nsITextInputProcessor.xhtml
@@ -0,0 +1,29 @@
+<?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"?>
+<window title="Testing nsITextInputProcessor behavior"
+ 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">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+window.openDialog("window_nsITextInputProcessor.xhtml", "_blank",
+ "chrome,width=600,height=600,noopener", window);
+
+]]>
+</script>
+</window>
diff --git a/dom/base/test/chrome/test_permission_hasValidTransientUserActivation.xhtml b/dom/base/test/chrome/test_permission_hasValidTransientUserActivation.xhtml
new file mode 100644
index 0000000000..06675a90ad
--- /dev/null
+++ b/dom/base/test/chrome/test_permission_hasValidTransientUserActivation.xhtml
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+ Tests that the hasValidTransientUserGestureActivation attribute on permission requests is set correctly.
+-->
+<window title="hasValidTransientUserGestureActivation test" 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 xmlns="http://www.w3.org/1999/xhtml">
+ <iframe id="frame" src="https://example.com/chrome/dom/base/test/chrome/dummy.html" />
+ </body>
+
+ <script type="application/javascript">
+ <![CDATA[
+ const {Integration} = ChromeUtils.import("resource://gre/modules/Integration.jsm");
+
+ SimpleTest.waitForExplicitFinish();
+
+ let frame = document.getElementById("frame");
+
+ function checkPermissionRequest(permission, hasValidTransientUserGestureActivation) {
+ return new Promise(function(resolve) {
+ let TestIntegration = (base) => ({
+ __proto__: base,
+ createPermissionPrompt(type, request) {
+ is(type, permission, `Has correct permission type ${permission}.`);
+ is(request.hasValidTransientUserGestureActivation, hasValidTransientUserGestureActivation,
+ "The hasValidTransientUserGestureActivation attribute is set correctly.");
+ Integration.contentPermission.unregister(TestIntegration);
+ resolve();
+ return { prompt() {} };
+ },
+ });
+ Integration.contentPermission.register(TestIntegration);
+ });
+ }
+
+ async function runTest() {
+ await SpecialPowers.setBoolPref("dom.webnotifications.allowcrossoriginiframe", true);
+
+ // Test programmatic request for persistent storage.
+ let request = checkPermissionRequest("persistent-storage", false);
+ navigator.storage.persist();
+ await request;
+
+ // Test user-initiated request for persistent storage.
+ request = checkPermissionRequest("persistent-storage", true);
+ document.notifyUserGestureActivation();
+ navigator.storage.persist();
+ await request;
+ content.document.clearUserGestureActivation();
+
+ // Test programmatic request for geolocation.
+ request = checkPermissionRequest("geolocation", false);
+ navigator.geolocation.getCurrentPosition(() => {});
+ await request;
+
+ // Test user-initiated request for geolocation.
+ request = checkPermissionRequest("geolocation", true);
+ document.notifyUserGestureActivation();
+ navigator.geolocation.getCurrentPosition(() => {});
+ await request;
+ document.clearUserGestureActivation();
+
+ // Notifications need to be tested in an HTTPS frame, because
+ // chrome:// URLs are whitelisted.
+ let frameWin = frame.contentWindow;
+
+ // Test programmatic request for notifications.
+ request = checkPermissionRequest("desktop-notification", false);
+ frameWin.Notification.requestPermission();
+ await request;
+
+ // Test user-initiated request for notifications.
+ request = checkPermissionRequest("desktop-notification", true);
+ frameWin.document.notifyUserGestureActivation();
+ frameWin.Notification.requestPermission();
+ await request;
+ frameWin.document.clearUserGestureActivation();
+
+ await SpecialPowers.clearUserPref("dom.webnotifications.allowcrossoriginiframe");
+ }
+
+ frame.addEventListener("load", function() {
+ runTest().then(() => SimpleTest.finish());
+ });
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_range_getClientRectsAndTexts.html b/dom/base/test/chrome/test_range_getClientRectsAndTexts.html
new file mode 100644
index 0000000000..10eddaf522
--- /dev/null
+++ b/dom/base/test/chrome/test_range_getClientRectsAndTexts.html
@@ -0,0 +1,74 @@
+<html>
+<head>
+<meta charset="utf-8">
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<script>
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ let range = document.createRange();
+
+ let attempts = [
+ {startNode: "one", start: 0, endNode: "one", end: 0, textList: [], message: "Empty rect"},
+ {startNode: "one", start: 2, endNode: "one", end: 6, textList: ["l on"], message: "Single line"},
+ {startNode: "implicit", start: 6, endNode: "implicit", end: 12, textList: ["it bre"], message: "Implicit break"},
+ {startNode: "two.a", start: 1, endNode: "two.b", end: 2, textList: ["wo", "", "li"], message: "Two lines"},
+ {startNode: "embed.a", start: 7, endNode: "embed.b", end: 2, textList: ["th ", "simple nested", " ", "te"], message: "Simple nested"},
+ {startNode: "deep.a", start: 2, endNode: "deep.b", end: 2, textList: ["ne with ", "complex, more deeply nested", " ", "te"], message: "Complex nested"},
+ {startNode: "image.a", start: 7, endNode: "image.b", end: 2, textList: ["th inline ", "", " ", "im"], message: "Inline image"},
+ {startNode: "hyphen1", start: 0, endNode: "hyphen1", end: 3, textList: ["a\u00AD", "b"], message: "Shy hyphen (active)"},
+ {startNode: "hyphen2", start: 0, endNode: "hyphen2", end: 3, textList: ["c\u00ADd"], message: "Shy hyphen (inactive)"},
+ {startNode: "hyphen2", start: 0, endNode: "hyphen2", end: 2, textList: ["c\u00AD"], message: "Shy hyphen (inactive, trailing)"},
+ {startNode: "hyphen2", start: 1, endNode: "hyphen2", end: 3, textList: ["\u00ADd"], message: "Shy hyphen (inactive, leading)"},
+ {startNode: "uc", start: 0, endNode: "uc", end: 2, textList: ["EF"], message: "UC transform"},
+ {startNode: "pre", start: 0, endNode: "pre", end: 3, textList: ["g\n", "h"], message: "pre with break"},
+ ];
+
+ for (let attempt of attempts) {
+ range.setStart(document.getElementById(attempt.startNode).childNodes[0], attempt.start);
+ range.setEnd(document.getElementById(attempt.endNode).childNodes[0], attempt.end);
+
+ let result = range.getClientRectsAndTexts();
+
+ is(result.textList.length, attempt.textList.length, attempt.message + " range has expected number of texts.");
+ let i = 0;
+ for (let text of result.textList) {
+ is(text, attempt.textList[i], attempt.message + " matched text index " + i + ".");
+ i++;
+ }
+ }
+
+ SimpleTest.finish();
+}
+</script>
+</head>
+<body onLoad="runTests()">
+
+<div id="one">All on one line</div>
+
+<div id="implicit">Implicit
+break in one line</div>
+
+<div id="two.a">Two<br/
+><span id="two.b">lines</span></div>
+
+<div id="embed.a">Line with <span>simple nested</span> <span id="embed.b">text</span></div>
+
+<div id="deep.a">Line with <span>complex, <span>more <span>deeply <span>nested</span></span></span></span> <span id="deep.b">text</span></div>
+
+<div id="image.a">Line with inline <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAG0lEQVR42mP8z0A%2BYKJA76jmUc2jmkc1U0EzACKcASfOgGoMAAAAAElFTkSuQmCC" width="20" height="20"/> <span id="image.b">image</span></div>
+
+<div id="hyphen1" style="width:0">a&shy;b</div>
+
+<div id="hyphen2" style="width:100px">c&shy;d</div>
+
+<div id="uc" style="text-transform:uppercase">ef</div>
+
+<pre id="pre">g
+h</pre>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/chrome/test_swapFrameLoaders.xhtml b/dom/base/test/chrome/test_swapFrameLoaders.xhtml
new file mode 100644
index 0000000000..4ea11a1a62
--- /dev/null
+++ b/dom/base/test/chrome/test_swapFrameLoaders.xhtml
@@ -0,0 +1,25 @@
+<?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=1242644
+Test swapFrameLoaders with different frame types and remoteness
+-->
+<window title="Mozilla Bug 1242644"
+ 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=1242644"
+ target="_blank">Mozilla Bug 1242644</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ SimpleTest.waitForExplicitFinish();
+
+ window.openDialog("window_swapFrameLoaders.xhtml", "bug1242644",
+ "chrome,width=600,height=600,noopener", window);
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/test_title.xhtml b/dom/base/test/chrome/test_title.xhtml
new file mode 100644
index 0000000000..33b3fd0220
--- /dev/null
+++ b/dom/base/test/chrome/test_title.xhtml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=481777
+-->
+<window title="Mozilla Bug 481777"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></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=481777"
+ target="_blank">Mozilla Bug 481777</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 481777 **/
+
+ SimpleTest.waitForExplicitFinish();
+ window.openDialog("title_window.xhtml", "bug481777",
+ "chrome,width=100,height=100,noopener", window);
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/test_windowroot.xhtml b/dom/base/test/chrome/test_windowroot.xhtml
new file mode 100644
index 0000000000..6f1c29095b
--- /dev/null
+++ b/dom/base/test/chrome/test_windowroot.xhtml
@@ -0,0 +1,18 @@
+<?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"?>
+<window title="Test window.windowRoot"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript"><![CDATA[
+ var root = window.windowRoot;
+ ok(WindowRoot.isInstance(root), "windowRoot should be a WindowRoot");
+ ]]></script>
+</window>
diff --git a/dom/base/test/chrome/title_window.xhtml b/dom/base/test/chrome/title_window.xhtml
new file mode 100644
index 0000000000..87a2769eb8
--- /dev/null
+++ b/dom/base/test/chrome/title_window.xhtml
@@ -0,0 +1,197 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<window title="Mozilla Bug 481777 subwindow"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="runTests()">
+
+ <iframe type="content" id="html1" src="data:text/html,&lt;html&gt;&lt;head&gt;&lt;title id='t'&gt;Test&lt;/title&gt;&lt;/head&gt;&lt;/html&gt;"/>
+ <iframe type="content" id="html2" src="data:text/html,&lt;html&gt;&lt;head&gt;&lt;title id='t'&gt;Test&lt;/title&gt;&lt;title&gt;Foo&lt;/title&gt;&lt;/head&gt;&lt;/html&gt;"/>
+ <iframe type="content" id="html3" src="data:text/html,&lt;html&gt;&lt;/html&gt;"/>
+ <iframe type="content" id="xhtml1" src="data:text/xml,&lt;html xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;body&gt;&lt;title id='t'&gt;Test&lt;/title&gt;&lt;/body&gt;&lt;/html&gt;"/>
+ <iframe type="content" id="xhtml2" src="data:text/xml,&lt;title xmlns='http://www.w3.org/1999/xhtml'&gt;Test&lt;/title&gt;"/>
+ <iframe type="content" id="xhtml3" src="data:text/xml,&lt;title xmlns='http://www.w3.org/1999/xhtml'&gt;Te&lt;div&gt;bogus&lt;/div&gt;st&lt;/title&gt;"/>
+ <iframe type="content" id="xhtml4" src="data:text/xml,&lt;html xmlns='http://www.w3.org/1999/xhtml'/>"/>
+ <iframe type="content" id="xhtml5" src="data:text/xml,&lt;html xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;head/>&lt;/html&gt;"/>
+ <iframe type="content" id="xhtml6" src="data:text/xml,&lt;html xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;head&gt;&lt;style/>&lt;/head&gt;&lt;/html&gt;"/>
+ <iframe id="xul1" src="file_title.xhtml"/>
+ <iframe id="xul2" src="file_title.xhtml"/>
+ <iframe type="content" id="svg1" src="data:text/xml,&lt;svg xmlns='http://www.w3.org/2000/svg'&gt;&lt;title id='t'&gt;Test&lt;/title&gt;&lt;/svg&gt;"/>
+ <iframe type="content" id="svg2" src="data:text/xml,&lt;svg xmlns='http://www.w3.org/2000/svg'&gt;&lt;title id='t'&gt;Test&lt;/title&gt;&lt;/svg&gt;"/>
+
+ <script type="application/javascript">
+ <![CDATA[
+ var imports = [ "SimpleTest", "is", "isnot", "ok" ];
+ for (var name of imports) {
+ window[name] = window.arguments[0][name];
+ }
+
+ function testStatics() {
+ function testStatic(id, expect, description) {
+ is(document.getElementById(id).contentDocument.title, expect, description);
+ }
+
+ testStatic("html1", "Test", "HTML <title>");
+ testStatic("html2", "Test", "choose the first HTML <title>");
+ testStatic("html3", "", "No title");
+ testStatic("xhtml1", "Test", "XHTML <title> in body");
+ testStatic("xhtml2", "Test", "XHTML <title> as root element");
+ testStatic("xhtml3", "Test", "XHTML <title> containing an element");
+ testStatic("xul1", "Test", "XUL <window> title attribute");
+ testStatic("svg1", "Test", "SVG <title>");
+
+ // This one does nothing and won't fire an event
+ document.getElementById("xhtml4").contentDocument.title = "Hello";
+ is(document.getElementById("xhtml4").contentDocument.title, "", "Setting 'title' does nothing with no <head>");
+ }
+
+ function testDynamics() {
+ var inProgress = {};
+ var inProgressDoc = {};
+ var inProgressWin = {};
+ function testDynamic(id, expect, description, op, checkDOM) {
+ inProgress[description] = true;
+ inProgressDoc[description] = true;
+ inProgressWin[description] = true;
+ var frame = document.getElementById(id);
+
+ function listener(ev) {
+ inProgress[description] = false;
+ is(frame.contentDocument.title, expect, "'title': " + description);
+ is(frame.contentDocument, ev.target, "Unexpected target: " + description);
+ if (typeof(checkDOM) != "undefined") {
+ checkDOM(frame.contentDocument, "DOM: " + description);
+ }
+ }
+
+ function listener2(ev) {
+ inProgressDoc[description] = false;
+ }
+ function listener3(ev) {
+ inProgressWin[description] = false;
+ }
+ frame.addEventListener("DOMTitleChanged", listener, false);
+ frame.contentDocument.addEventListener("DOMTitleChanged", listener2, false);
+ frame.contentWindow.addEventListener("DOMTitleChanged", listener3, false);
+
+ op(frame.contentDocument);
+ }
+
+ var dynamicTests = [
+ [ "html1", "Hello", "Setting HTML <title> text contents",
+ function(doc){
+ var t = doc.getElementById("t"); t.textContent = "Hello";
+ } ],
+ [ "html2", "Foo", "Removing HTML <title>",
+ function(doc){
+ var t = doc.getElementById("t"); t.remove();
+ } ],
+ [ "html3", "Hello", "Appending HTML <title> element to root element",
+ function(doc){
+ var t = doc.createElement("title"); t.textContent = "Hello"; doc.documentElement.appendChild(t);
+ } ],
+ [ "xhtml3", "Hello", "Setting 'title' clears existing <title> contents",
+ function(doc){
+ doc.title = "Hello";
+ },
+ function(doc, desc) {
+ is(doc.documentElement.firstChild.data, "Hello", desc);
+ is(doc.documentElement.firstChild.nextSibling, null, desc);
+ } ],
+ [ "xhtml5", "Hello", "Setting 'title' works with a <head>",
+ function(doc){
+ doc.title = "Hello";
+ },
+ function(doc, desc) {
+ var head = doc.documentElement.firstChild;
+ var title = head.firstChild;
+ is(title.tagName.toLowerCase(), "title", desc);
+ is(title.firstChild.data, "Hello", desc);
+ is(title.firstChild.nextSibling, null, desc);
+ is(title.nextSibling, null, desc);
+ } ],
+ [ "xhtml6", "Hello", "Setting 'title' appends to <head>",
+ function(doc){
+ doc.title = "Hello";
+ },
+ function(doc, desc) {
+ var head = doc.documentElement.firstChild;
+ is(head.firstChild.tagName.toLowerCase(), "style", desc);
+ var title = head.firstChild.nextSibling;
+ is(title.tagName.toLowerCase(), "title", desc);
+ is(title.firstChild.data, "Hello", desc);
+ is(title.firstChild.nextSibling, null, desc);
+ is(title.nextSibling, null, desc);
+ } ],
+ [ "xul1", "Hello", "Setting XUL <window> title attribute",
+ function(doc){
+ doc.documentElement.setAttribute("title", "Hello");
+ } ],
+ [ "xul2", "Hello", "Setting 'title' in XUL",
+ function(doc){
+ doc.title = "Hello";
+ },
+ function(doc, desc) {
+ is(doc.documentElement.getAttribute("title"), "Hello", desc);
+ is(doc.documentElement.firstChild, null, desc);
+ } ],
+ [ "svg1", "Hello", "Setting SVG <title> text contents",
+ function(doc){
+ var t = doc.getElementById("t"); t.textContent = "Hello";
+ } ],
+ [ "svg2", "", "Removing SVG <title>",
+ function(doc){
+ var t = doc.getElementById("t"); t.remove();
+ } ] ];
+
+ var titleWindow = window;
+
+ function runIndividualTest(i) {
+ if (i == dynamicTests.length) {
+ // Closing the window will nuke the global properties, since this
+ // function is not really running on this window... or something
+ // like that. Thanks, executeSoon!
+ var tester = SimpleTest;
+ window.close();
+ tester.finish();
+ } else {
+ var parameters = dynamicTests[i];
+ var testElementId = parameters[0];
+ var testExpectedValue = parameters[1];
+ var testDescription = parameters[2];
+ var testOp = parameters[3];
+ var testCheckDOM = parameters[4];
+
+ function checkTest() {
+ ok(!inProgress[testDescription],
+ testDescription + ": DOMTitleChange not fired");
+ ok(inProgressDoc[testDescription],
+ testDescription + ": DOMTitleChange fired on content document");
+ ok(inProgressWin[testDescription],
+ testDescription + ": DOMTitleChange fired on content window");
+ // Run the next test in the context of the parent XUL window.
+ titleWindow.setTimeout(runIndividualTest, 0, i+1);
+ }
+ function spinEventLoopOp(doc) {
+ // Perform the test's operations.
+ testOp(doc);
+ // Spin the associated window's event loop to ensure we
+ // drain any asynchronous changes and fire associated
+ // events.
+ doc.defaultView.setTimeout(checkTest, 0);
+ }
+
+ testDynamic(testElementId, testExpectedValue, testDescription,
+ spinEventLoopOp, testCheckDOM);
+ }
+ }
+
+ window.setTimeout(runIndividualTest, 0, 0);
+ }
+
+ function runTests() {
+ testStatics();
+ testDynamics();
+ }
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/chrome/window_chromeOuterWindowID.xhtml b/dom/base/test/chrome/window_chromeOuterWindowID.xhtml
new file mode 100644
index 0000000000..268409c1bf
--- /dev/null
+++ b/dom/base/test/chrome/window_chromeOuterWindowID.xhtml
@@ -0,0 +1,14 @@
+<?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=1474662
+Test that the chromeOuterWindowID on the MessageManager interface
+works, and that it properly updates when swapping frameloaders between
+windows.
+-->
+<window title="Mozilla Bug 1242644"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <browser id="non-remote" nodefaultsrc="true" type="content" flex="1"/>
+ <browser id="remote" remote="true" nodefaultsrc="true" type="content" flex="1"/>
+</window> \ No newline at end of file
diff --git a/dom/base/test/chrome/window_nsITextInputProcessor.xhtml b/dom/base/test/chrome/window_nsITextInputProcessor.xhtml
new file mode 100644
index 0000000000..291a9e4324
--- /dev/null
+++ b/dom/base/test/chrome/window_nsITextInputProcessor.xhtml
@@ -0,0 +1,4750 @@
+<?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"?>
+<window title="Testing nsITextInputProcessor behavior"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onunload="onunload();">
+<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+<body xmlns="http://www.w3.org/1999/xhtml">
+<div id="display">
+<input id="input" type="text"/><input id="anotherInput" type="text"/><br/>
+<textarea></textarea>
+<iframe id="iframe" width="300" height="150"
+ src="data:text/html,&lt;textarea id='textarea' cols='20' rows='4'&gt;&lt;/textarea&gt;"></iframe><br/>
+<div contenteditable=""><br/></div>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+var SimpleTest = window.arguments[0].SimpleTest;
+
+SimpleTest.waitForFocus(runTests, window);
+
+function getHTMLEditor(aWindow) {
+ return SpecialPowers.wrap(aWindow).docShell.editingSession?.getEditorForWindow(aWindow);
+}
+
+function ok(aCondition, aMessage)
+{
+ SimpleTest.ok(aCondition, aMessage);
+}
+
+function is(aLeft, aRight, aMessage)
+{
+ SimpleTest.is(aLeft, aRight, aMessage);
+}
+
+function isnot(aLeft, aRight, aMessage)
+{
+ SimpleTest.isnot(aLeft, aRight, aMessage);
+}
+
+function todo_is(aLeft, aRight, aMessage)
+{
+ SimpleTest.todo_is(aLeft, aRight, aMessage);
+}
+
+function info(aMessage) {
+ SimpleTest.info(aMessage);
+}
+
+function finish()
+{
+ window.close();
+}
+
+function onunload()
+{
+ SimpleTest.finish();
+}
+
+function checkInputEvent(aEvent, aCancelable, aIsComposing, aInputType, aData, aDescription) {
+ if (aEvent.type !== "input" && aEvent.type !== "beforeinput") {
+ throw new Error(`${aDescription}"${aEvent.type}" is not InputEvent`);
+ }
+ ok(InputEvent.isInstance(aEvent), `${aDescription}"${aEvent.type}" event should be dispatched with InputEvent interface`);
+ is(aEvent.cancelable, aCancelable, `${aDescription}"${aEvent.type}" event should ${aCancelable ? "be" : "not be"} cancelable`);
+ is(aEvent.bubbles, true, `${aDescription}"${aEvent.type}" event should always bubble`);
+ is(aEvent.isComposing, aIsComposing, `${aDescription}isComposing of "${aEvent.type}" event should be ${aIsComposing}`);
+ is(aEvent.inputType, aInputType, `${aDescription}inputType of "${aEvent.type}" event should be "${aInputType}"`);
+ is(aEvent.data, aData, `${aDescription}data of "${aEvent.type}" event should be "${aData}"`);
+ is(aEvent.dataTransfer, null, `${aDescription}dataTransfer of "${aEvent.type}" event should be null`);
+ is(aEvent.getTargetRanges().length, 0, `${aDescription}getTargetRanges() of "${aEvent.type}" event should return empty array`);
+}
+
+const kIsMac = (navigator.platform.indexOf("Mac") == 0);
+
+const iframe = document.getElementById("iframe");
+let childWindow = iframe.contentWindow;
+let textareaInFrame;
+const input = document.getElementById("input");
+const textarea = document.querySelector("textarea");
+const otherWindow = window.arguments[0];
+const otherDocument = otherWindow.document;
+const inputInChildWindow = otherDocument.getElementById("input");
+const contenteditable = document.querySelector("div[contenteditable]");
+
+const kLF = navigator.platform.startsWith("Win") ? "\r\n" : "\n";
+function getNativeText(aXPText)
+{
+ if (kLF == "\n") {
+ return aXPText;
+ }
+ return aXPText.replace(/\n/g, kLF);
+}
+
+function createTIP()
+{
+ return Cc["@mozilla.org/text-input-processor;1"].
+ createInstance(Ci.nsITextInputProcessor);
+}
+
+function runBeginInputTransactionMethodTests()
+{
+ var description = "runBeginInputTransactionMethodTests: ";
+ input.value = "";
+ input.focus();
+
+ var simpleCallback = function (aTIP, aNotification)
+ {
+ switch (aNotification.type) {
+ case "request-to-commit":
+ aTIP.commitComposition();
+ break;
+ case "request-to-cancel":
+ aTIP.cancelComposition();
+ break;
+ }
+ return true;
+ };
+
+ var TIP1 = createTIP();
+ var TIP2 = createTIP();
+ isnot(TIP1, TIP2,
+ description + "TIP instances should be different");
+
+ // beginInputTransaction() and beginInputTransactionForTests() can take ownership if there is no composition.
+ ok(TIP1.beginInputTransaction(window, simpleCallback),
+ description + "TIP1.beginInputTransaction(window) should succeed because there is no composition");
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests(window) should succeed because there is no composition");
+ ok(TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2.beginInputTransaction(window) should succeed because there is no composition");
+ ok(TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests(window) should succeed because there is no composition");
+
+ // Start composition with TIP1, then, other TIPs cannot take ownership during a composition.
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
+ var composingStr = "foo";
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ ok(TIP1.flushPendingComposition(),
+ description + "TIP1.flushPendingComposition() should return true becuase it should be valid composition");
+ is(input.value, composingStr,
+ description + "The input element should have composing string");
+
+ // Composing nsITextInputProcessor instance shouldn't allow initialize it again.
+ try {
+ TIP1.beginInputTransaction(window, simpleCallback);
+ ok(false,
+ "TIP1.beginInputTransaction(window) should cause throwing an exception because it's composing with different purpose");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(window) should cause throwing an exception including NS_ERROR_ALREADY_INITIALIZED because it's composing for tests");
+ }
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow);
+ ok(false,
+ "TIP1.beginInputTransactionForTests(otherWindow) should cause throwing an exception because it's composing on different window");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow) should cause throwing an exception including NS_ERROR_ALREADY_INITIALIZED because it's composing on this window");
+ }
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests(window) should succeed because TextEventDispatcher was initialized with same purpose");
+ ok(TIP1.beginInputTransactionForTests(childWindow),
+ description + "TIP1.beginInputTransactionForTests(childWindow) should succeed because TextEventDispatcher was initialized with same purpose and is shared by window and childWindow");
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2.beginInputTransaction(window) should not succeed because there is composition synthesized by TIP1");
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests(window) should not succeed because there is composition synthesized by TIP1");
+ ok(!TIP2.beginInputTransaction(childWindow, simpleCallback),
+ description + "TIP2.beginInputTransaction(childWindow) should not succeed because there is composition synthesized by TIP1");
+ ok(!TIP2.beginInputTransactionForTests(childWindow),
+ description + "TIP2.beginInputTransactionForTests(childWindow) should not succeed because there is composition synthesized by TIP1");
+ ok(TIP2.beginInputTransaction(otherWindow, simpleCallback),
+ description + "TIP2.beginInputTransaction(otherWindow) should succeed because there is composition synthesized by TIP1 but it's in other window");
+ ok(TIP2.beginInputTransactionForTests(otherWindow),
+ description + "TIP2.beginInputTransactionForTests(otherWindow) should succeed because there is composition synthesized by TIP1 but it's in other window");
+
+ // Let's confirm that the composing string is NOT committed by above tests.
+ TIP1.commitComposition();
+ is(input.value, composingStr,
+ description + "TIP1.commitString() without specifying commit string should commit current composition with the last composing string");
+ ok(!TIP1.hasComposition,
+ description + "TIP1.commitString() without specifying commit string should've end composition");
+
+ ok(TIP1.beginInputTransaction(window, simpleCallback),
+ description + "TIP1.beginInputTransaction() should succeed because there is no composition #2");
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition #2");
+ ok(TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests() should succeed because the composition was already committed #2");
+
+ // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during startComposition().
+ var events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ input.removeEventListener(aEvent.type, arguments.callee, false);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from compositionstart event handler during TIP1.startComposition();");
+ }, false);
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.startComposition();
+ is(events.length, 1,
+ description + "compositionstart event should be fired by TIP1.startComposition()");
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during flushPendingComposition().
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from compositionstart event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from compositionupdate event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from text event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ is(events.length, 5,
+ description + "compositionstart, compositionupdate, text, beforeinput and input events should be fired by TIP1.flushPendingComposition()");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", composingStr, description);
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, true, "insertCompositionText", composingStr, description);
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during commitComposition().
+ events = [];
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from text event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from compositionend event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ TIP1.commitComposition();
+ is(events.length, 4,
+ description + "text, beforeinput, compositionend and input events should be fired by TIP1.commitComposition()");
+ is(events[0].type, "text",
+ description + "events[0] should be text");
+ is(events[1].type, "beforeinput",
+ description + "events[1] should be beforeinput");
+ checkInputEvent(events[1], false, true, "insertCompositionText", composingStr, description);
+ is(events[2].type, "compositionend",
+ description + "events[2] should be compositionend");
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertCompositionText", composingStr, description);
+
+ // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during commitCompositionWith("bar").
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from compositionstart event handler during TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction during compositionupdate event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction during text event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction during compositionend event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction during beforeinput event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction during input event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.commitCompositionWith("bar");
+ is(events.length, 6,
+ description + "compositionstart, compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.commitCompositionWith(\"bar\")");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", "bar", description);
+ is(events[4].type, "compositionend",
+ description + "events[4] should be compositionend");
+ is(events[5].type, "input",
+ description + "events[5] should be input");
+ checkInputEvent(events[5], false, false, "insertCompositionText", "bar", description);
+
+ // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during cancelComposition().
+ events = [];
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from compositionupdate event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from text event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from compositionend event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ TIP1.cancelComposition();
+ is(events.length, 5,
+ description + "compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.cancelComposition()");
+ is(events[0].type, "compositionupdate",
+ description + "events[0] should be compositionupdate");
+ is(events[1].type, "text",
+ description + "events[1] should be text");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], false, true, "insertCompositionText", "", description);
+ is(events[3].type, "compositionend",
+ description + "events[3] should be compositionend");
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, false, "insertCompositionText", "", description);
+
+ // Let's check if beginInputTransaction() fails to steal the rights of TextEventDispatcher during keydown() and keyup().
+ events = [];
+ TIP1.beginInputTransaction(window, simpleCallback);
+ input.addEventListener("keydown", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from keydown event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("keypress", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from keypress event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from beforeinput event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from input event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("keyup", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransaction(window, simpleCallback),
+ description + "TIP2 shouldn't be able to begin input transaction from keyup event handler during a call of TIP1.keyup();");
+ }, {once: true});
+ var keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+ TIP1.keydown(keyA);
+ TIP1.keyup(keyA);
+ is(events.length, 5,
+ description + "keydown, keypress, beforeinput, input, keyup events should be fired by TIP1.keydown() and TIP1.keyup()");
+ is(events[0].type, "keydown",
+ description + "events[0] should be keydown");
+ is(events[1].type, "keypress",
+ description + "events[1] should be keypress");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], true, false, "insertText", "a", description);
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertText", "a", description);
+ is(events[4].type, "keyup",
+ description + "events[4] should be keyup");
+
+ // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during startComposition().
+ var events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ input.removeEventListener(aEvent.type, arguments.callee, false);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from compositionstart event handler during TIP1.startComposition();");
+ }, false);
+ TIP1.beginInputTransactionForTests(window);
+ TIP1.startComposition();
+ is(events.length, 1,
+ description + "compositionstart event should be fired by TIP1.startComposition()");
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during flushPendingComposition().
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from compositionstart event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from compositionupdate event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from text event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.flushPendingComposition();");
+ }, {once: true});
+ TIP1.beginInputTransactionForTests(window);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ is(events.length, 5,
+ description + "compositionstart, compositionupdate, text, beforeinput and input events should be fired by TIP1.flushPendingComposition()");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", composingStr, description);
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, true, "insertCompositionText", composingStr, description);
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during commitComposition().
+ events = [];
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from text event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from compositionend event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.commitComposition();");
+ }, {once: true});
+ TIP1.commitComposition();
+ is(events.length, 4,
+ description + "text, beforeinput, compositionend and input events should be fired by TIP1.commitComposition()");
+ is(events[0].type, "text",
+ description + "events[0] should be text");
+ is(events[1].type, "beforeinput",
+ description + "events[1] should be beforeinput");
+ checkInputEvent(events[1], false, true, "insertCompositionText", composingStr, description);
+ is(events[2].type, "compositionend",
+ description + "events[2] should be compositionend");
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertCompositionText", composingStr, description);
+
+ // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during commitCompositionWith("bar").
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from compositionstart event handler during TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests during compositionupdate event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests during text event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests during compositionend event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests during beforeinput event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests during input event handler TIP1.commitCompositionWith(\"bar\");");
+ }, {once: true});
+ TIP1.beginInputTransactionForTests(window);
+ TIP1.commitCompositionWith("bar");
+ is(events.length, 6,
+ description + "compositionstart, compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.commitCompositionWith(\"bar\")");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", "bar", description);
+ is(events[4].type, "compositionend",
+ description + "events[4] should be compositionend");
+ is(events[5].type, "input",
+ description + "events[5] should be input");
+ checkInputEvent(events[5], false, false, "insertCompositionText", "bar", description);
+
+ // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during cancelComposition().
+ events = [];
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from compositionupdate event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from text event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from compositionend event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.cancelComposition();");
+ }, {once: true});
+ TIP1.cancelComposition();
+ is(events.length, 5,
+ description + "compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.cancelComposition()");
+ is(events[0].type, "compositionupdate",
+ description + "events[0] should be compositionupdate");
+ is(events[1].type, "text",
+ description + "events[1] should be text");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], false, true, "insertCompositionText", "", description);
+ is(events[3].type, "compositionend",
+ description + "events[3] should be compositionend");
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, false, "insertCompositionText", "", description);
+
+ // Let's check if beginInputTransactionForTests() fails to steal the rights of TextEventDispatcher during keydown() and keyup().
+ events = [];
+ TIP1.beginInputTransactionForTests(window);
+ input.addEventListener("keydown", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests for tests from keydown event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("keypress", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from keypress event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from beforeinput event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from input event handler during a call of TIP1.keydown();");
+ }, {once: true});
+ input.addEventListener("keyup", function (aEvent) {
+ events.push(aEvent);
+ ok(!TIP2.beginInputTransactionForTests(window),
+ description + "TIP2 shouldn't be able to begin input transaction for tests from keyup event handler during a call of TIP1.keyup();");
+ }, {once: true});
+ var keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+ TIP1.keydown(keyA);
+ TIP1.keyup(keyA);
+ is(events.length, 5,
+ description + "keydown, keypress, beforeinput, input, keyup events should be fired by TIP1.keydown() and TIP1.keyup()");
+ is(events[0].type, "keydown",
+ description + "events[0] should be keydown");
+ is(events[1].type, "keypress",
+ description + "events[1] should be keypress");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], true, false, "insertText", "a", description);
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertText", "a", description);
+ is(events[4].type, "keyup",
+ description + "events[4] should be keyup");
+
+ // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during startComposition().
+ var events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during startComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during startComposition()");
+ }
+ }, {once: true});
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.startComposition();
+ is(events.length, 1,
+ description + "compositionstart event should be fired by TIP1.startComposition()");
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during flushPendingComposition().
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ is(events.length, 5,
+ description + "compositionstart, compositionupdate, text, beforeinput and input events should be fired by TIP1.flushPendingComposition()");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", composingStr, description);
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, true, "insertCompositionText", composingStr, description);
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during commitComposition().
+ events = [];
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ TIP1.commitComposition();
+ is(events.length, 4,
+ description + "text, beforeinput, compositionend and input events should be fired by TIP1.commitComposition()");
+ is(events[0].type, "text",
+ description + "events[0] should be text");
+ is(events[1].type, "beforeinput",
+ description + "events[1] should be beforeinput");
+ checkInputEvent(events[1], false, true, "insertCompositionText", composingStr, description);
+ is(events[2].type, "compositionend",
+ description + "events[2] should be compositionend");
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertCompositionText", composingStr, description);
+
+ // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during commitCompositionWith("bar");.
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.commitCompositionWith("bar");
+ is(events.length, 6,
+ description + "compositionstart, compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.commitCompositionWith(\"bar\")");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", "bar", description);
+ is(events[4].type, "compositionend",
+ description + "events[4] should be compositionend");
+ is(events[5].type, "input",
+ description + "events[5] should be input");
+ checkInputEvent(events[5], false, false, "insertCompositionText", "bar", description);
+
+ // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during cancelComposition();.
+ events = [];
+ TIP1.beginInputTransaction(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ TIP1.cancelComposition();
+ is(events.length, 5,
+ description + "compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.cancelComposition()");
+ is(events[0].type, "compositionupdate",
+ description + "events[0] should be compositionupdate");
+ is(events[1].type, "text",
+ description + "events[1] should be text");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], false, true, "insertCompositionText", "", description);
+ is(events[3].type, "compositionend",
+ description + "events[3] should be compositionend");
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, false, "insertCompositionText", "", description);
+
+ // Let's check if beginInputTransaction() with another window fails to begin new input transaction with different TextEventDispatcher during keydown() and keyup();.
+ events = [];
+ TIP1.beginInputTransaction(window, simpleCallback);
+ input.addEventListener("keydown", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keydown\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keydown\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("keypress", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keypress\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keypress\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("keyup", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransaction(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keyup\" should throw an exception during keyup()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransaction(otherWindow, simpleCallback) called from \"keyup\" should cause NS_ERROR_ALREADY_INITIALIZED during keyup()");
+ }
+ }, {once: true});
+ var keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+ TIP1.keydown(keyA);
+ TIP1.keyup(keyA);
+ is(events.length, 5,
+ description + "keydown, keypress, beforeinput, input, keyup events should be fired by TIP1.keydown() and TIP1.keyup()");
+ is(events[0].type, "keydown",
+ description + "events[0] should be keydown");
+ is(events[1].type, "keypress",
+ description + "events[1] should be keypress");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], true, false, "insertText", "a", description);
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertText", "a", description);
+ is(events[4].type, "keyup",
+ description + "events[4] should be keyup");
+
+ // Let's check if beginInputTransactionForTests() with another window fails to begin new input transaction with different TextEventDispatcher during startComposition().
+ var events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during startComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during startComposition()");
+ }
+ }, {once: true});
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ TIP1.startComposition();
+ is(events.length, 1,
+ description + "compositionstart event should be fired by TIP1.startComposition()");
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransactionForTests() with another window fails to begin new input transaction with different TextEventDispatcher during flushPendingComposition().
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should throw an exception during flushPendingComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during flushPendingComposition()");
+ }
+ }, {once: true});
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ is(events.length, 5,
+ description + "compositionstart, compositionupdate, text, beforeinput and input events should be fired by TIP1.flushPendingComposition()");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", composingStr, description);
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, true, "insertCompositionText", composingStr, description);
+ TIP1.cancelComposition();
+
+ // Let's check if beginInputTransactionForTests() with another window fails to begin new input transaction with different TextEventDispatcher during commitComposition().
+ events = [];
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should throw an exception during commitComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during commitComposition()");
+ }
+ }, {once: true});
+ TIP1.commitComposition();
+ is(events.length, 4,
+ description + "text, beforeinput, compositionend and input events should be fired by TIP1.commitComposition()");
+ is(events[0].type, "text",
+ description + "events[0] should be text");
+ is(events[1].type, "beforeinput",
+ description + "events[1] should be beforeinput");
+ checkInputEvent(events[1], false, true, "insertCompositionText", composingStr, description);
+ is(events[2].type, "compositionend",
+ description + "events[2] should be compositionend");
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertCompositionText", composingStr, description);
+
+ // Let's check if beginInputTransactionForTests() with another window fails to begin new input transaction with different TextEventDispatcher during commitCompositionWith("bar");.
+ events = [];
+ input.addEventListener("compositionstart", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionstart\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionstart\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should throw an exception during commitCompositionWith(\"bar\")");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during commitCompositionWith(\"bar\")");
+ }
+ }, {once: true});
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ TIP1.commitCompositionWith("bar");
+ is(events.length, 6,
+ description + "compositionstart, compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.commitCompositionWith(\"bar\")");
+ is(events[0].type, "compositionstart",
+ description + "events[0] should be compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "events[1] should be compositionupdate");
+ is(events[2].type, "text",
+ description + "events[2] should be text");
+ is(events[3].type, "beforeinput",
+ description + "events[3] should be beforeinput");
+ checkInputEvent(events[3], false, true, "insertCompositionText", "bar", description);
+ is(events[4].type, "compositionend",
+ description + "events[4] should be compositionend");
+ is(events[5].type, "input",
+ description + "events[5] should be input");
+ checkInputEvent(events[5], false, false, "insertCompositionText", "bar", description);
+
+ // Let's check if beginInputTransactionForTests() with another window fails to begin new input transaction with different TextEventDispatcher during cancelComposition();.
+ events = [];
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition();
+ input.addEventListener("compositionupdate", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionupdate\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionupdate\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("text", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"text\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("compositionend", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionend\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"compositionend\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should throw an exception during cancelComposition()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during cancelComposition()");
+ }
+ }, {once: true});
+ TIP1.cancelComposition();
+ is(events.length, 5,
+ description + "compositionupdate, text, beforeinput, compositionend and input events should be fired by TIP1.cancelComposition()");
+ is(events[0].type, "compositionupdate",
+ description + "events[0] should be compositionupdate");
+ is(events[1].type, "text",
+ description + "events[1] should be text");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], false, true, "insertCompositionText", "", description);
+ is(events[3].type, "compositionend",
+ description + "events[3] should be compositionend");
+ is(events[4].type, "input",
+ description + "events[4] should be input");
+ checkInputEvent(events[4], false, false, "insertCompositionText", "", description);
+
+ // Let's check if beginInputTransactionForTests() with another window fails to begin new input transaction with different TextEventDispatcher during keydown() and keyup();.
+ events = [];
+ TIP1.beginInputTransactionForTests(window, simpleCallback);
+ input.addEventListener("keydown", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"keydown\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"keydown\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("keypress", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"keypress\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"keypress\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("beforeinput", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"beforeinput\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("input", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should throw an exception during keydown()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"input\" should cause NS_ERROR_ALREADY_INITIALIZED during keydown()");
+ }
+ }, {once: true});
+ input.addEventListener("keyup", function (aEvent) {
+ events.push(aEvent);
+ try {
+ TIP1.beginInputTransactionForTests(otherWindow, simpleCallback);
+ ok(false,
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"keyup\" should throw an exception during keyup()");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ALREADY_INITIALIZED"),
+ description + "TIP1.beginInputTransactionForTests(otherWindow, simpleCallback) called from \"keyup\" should cause NS_ERROR_ALREADY_INITIALIZED during keyup()");
+ }
+ }, {once: true});
+ var keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+ TIP1.keydown(keyA);
+ TIP1.keyup(keyA);
+ is(events.length, 5,
+ description + "keydown, keypress, beforeinput, input, keyup events should be fired by TIP1.keydown() and TIP1.keyup()");
+ is(events[0].type, "keydown",
+ description + "events[0] should be keydown");
+ is(events[1].type, "keypress",
+ description + "events[1] should be keypress");
+ is(events[2].type, "beforeinput",
+ description + "events[2] should be beforeinput");
+ checkInputEvent(events[2], true, false, "insertText", "a", description);
+ is(events[3].type, "input",
+ description + "events[3] should be input");
+ checkInputEvent(events[3], false, false, "insertText", "a", description);
+ is(events[4].type, "keyup",
+ description + "events[4] should be keyup");
+
+ // Let's check if startComposition() throws an exception after ownership is stolen.
+ input.value = "";
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
+ ok(TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests() should succeed because there is no composition");
+ try {
+ TIP1.startComposition();
+ ok(false,
+ description + "TIP1.startComposition() should cause throwing an exception because TIP2 took the ownership");
+ TIP1.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_NOT_INITIALIZED"),
+ description + "TIP1.startComposition() should cause throwing an exception including NS_ERROR_NOT_INITIALIZED");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not have commit string");
+ }
+
+ // Let's check if flushPendingComposition() throws an exception after ownership is stolen.
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
+ ok(TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests() should succeed because there is no composition");
+ input.value = "";
+ try {
+ TIP1.setPendingCompositionString(composingStr);
+ TIP1.appendClauseToPendingComposition(composingStr.length, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.flushPendingComposition()
+ ok(false,
+ description + "TIP1.flushPendingComposition() should cause throwing an exception because TIP2 took the ownership");
+ TIP1.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_NOT_INITIALIZED"),
+ description + "TIP1.flushPendingComposition() should cause throwing an exception including NS_ERROR_NOT_INITIALIZED");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not have commit string");
+ }
+
+ // Let's check if commitCompositionWith("bar") throws an exception after ownership is stolen.
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
+ ok(TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests() should succeed because there is no composition");
+ input.value = "";
+ try {
+ TIP1.commitCompositionWith("bar");
+ ok(false,
+ description + "TIP1.commitCompositionWith(\"bar\") should cause throwing an exception because TIP2 took the ownership");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_NOT_INITIALIZED"),
+ description + "TIP1.commitCompositionWith(\"bar\") should cause throwing an exception including NS_ERROR_NOT_INITIALIZED");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not have commit string");
+ }
+
+ // Let's check if keydown() throws an exception after ownership is stolen.
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
+ ok(TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests() should succeed because there is no composition");
+ input.value = "";
+ try {
+ var keyF = new KeyboardEvent("", { key: "f", code: "KeyF", keyCode: KeyboardEvent.DOM_VK_F });
+ TIP1.keydown(keyF);
+ ok(false,
+ description + "TIP1.keydown(keyF) should cause throwing an exception because TIP2 took the ownership");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_NOT_INITIALIZED"),
+ description + "TIP1.keydown(keyF) should cause throwing an exception including NS_ERROR_NOT_INITIALIZED");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not be modified");
+ }
+
+ // Let's check if keyup() throws an exception after ownership is stolen.
+ ok(TIP1.beginInputTransactionForTests(window),
+ description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
+ ok(TIP2.beginInputTransactionForTests(window),
+ description + "TIP2.beginInputTransactionForTests() should succeed because there is no composition");
+ input.value = "";
+ try {
+ var keyF = new KeyboardEvent("", { key: "f", code: "KeyF", keyCode: KeyboardEvent.DOM_VK_F });
+ TIP1.keyup(keyF);
+ ok(false,
+ description + "TIP1.keyup(keyF) should cause throwing an exception because TIP2 took the ownership");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_NOT_INITIALIZED"),
+ description + "TIP1.keyup(keyF) should cause throwing an exception including NS_ERROR_NOT_INITIALIZED");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not be modified");
+ }
+
+ // aCallback of nsITextInputProcessor.beginInputTransaction() must not be omitted.
+ try {
+ TIP1.beginInputTransaction(window);
+ ok(false,
+ description + "TIP1.beginInputTransaction(window) should be failed since aCallback is omitted");
+ } catch (e) {
+ ok(e.message.includes("Not enough arguments"),
+ description + "TIP1.beginInputTransaction(window) should cause throwing an exception including \"Not enough arguments\" since aCallback is omitted");
+ }
+
+ // aCallback of nsITextInputProcessor.beginInputTransaction() must not be undefined.
+ try {
+ TIP1.beginInputTransaction(window, undefined);
+ ok(false,
+ description + "TIP1.beginInputTransaction(window, undefined) should be failed since aCallback is undefined");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "TIP1.beginInputTransaction(window, undefined) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE since aCallback is undefined");
+ }
+
+ // aCallback of nsITextInputProcessor.beginInputTransaction() must not be null.
+ try {
+ TIP1.beginInputTransaction(window, null);
+ ok(false,
+ description + "TIP1.beginInputTransaction(window, null) should be failed since aCallback is null");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "TIP1.beginInputTransaction(window, null) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE since aCallback is null");
+ }
+}
+
+function runReleaseTests()
+{
+ var description = "runReleaseTests(): ";
+
+ var TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ input.value = "";
+ input.focus();
+
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ is(input.value, "foo",
+ description + "the input should have composition string");
+
+ // Release the TIP
+ TIP = null;
+ // Needs to run GC forcibly for testing this.
+ Cu.forceGC();
+
+ is(input.value, "",
+ description + "the input should be empty because the composition should be canceled");
+
+ TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed #2");
+}
+
+function runCompositionTests()
+{
+ var description = "runCompositionTests(): ";
+
+ var TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ var events;
+
+ function reset()
+ {
+ events = [];
+ }
+
+ function handler(aEvent)
+ {
+ events.push({ "type": aEvent.type, "data": aEvent.data });
+ }
+
+ window.addEventListener("compositionstart", handler, false);
+ window.addEventListener("compositionupdate", handler, false);
+ window.addEventListener("compositionend", handler, false);
+
+ input.value = "";
+ input.focus();
+
+ // nsITextInputProcessor.startComposition()
+ reset();
+ TIP.startComposition();
+ is(events.length, 1,
+ description + "startComposition() should cause only compositionstart");
+ is(events[0].type, "compositionstart",
+ description + "startComposition() should cause only compositionstart");
+ is(input.value, "",
+ description + "startComposition() shouldn't modify the focused editor");
+
+ // Setting composition string "foo" as a raw clause
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+
+ reset();
+ TIP.flushPendingComposition();
+ is(events.length, 1,
+ description + "flushPendingComposition() after startComposition() should cause compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "flushPendingComposition() after startComposition() should cause compositionupdate");
+ is(events[0].data, "foo",
+ description + "compositionupdate caused by flushPendingComposition() should have new composition string in its data");
+ is(input.value, "foo",
+ description + "modifying composition string should cause modifying the focused editor");
+
+ // Changing the raw clause to a selected clause
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_SELECTED_CLAUSE);
+
+ reset();
+ TIP.flushPendingComposition();
+ is(events.length, 0,
+ description + "flushPendingComposition() changing only clause information shouldn't cause compositionupdate");
+ is(input.value, "foo",
+ description + "modifying composition clause shouldn't cause modifying the focused editor");
+
+ // Separating the selected clause to two clauses
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(2, TIP.ATTR_SELECTED_CLAUSE);
+ TIP.appendClauseToPendingComposition(1, TIP.ATTR_CONVERTED_CLAUSE);
+ TIP.setCaretInPendingComposition(2);
+
+ reset();
+ TIP.flushPendingComposition();
+ is(events.length, 0,
+ description + "flushPendingComposition() separating a clause information shouldn't cause compositionupdate");
+ is(input.value, "foo",
+ description + "separating composition clause shouldn't cause modifying the focused editor");
+
+ // Modifying the composition string
+ TIP.setPendingCompositionString("FOo");
+ TIP.appendClauseToPendingComposition(2, TIP.ATTR_SELECTED_CLAUSE);
+ TIP.appendClauseToPendingComposition(1, TIP.ATTR_CONVERTED_CLAUSE);
+ TIP.setCaretInPendingComposition(2);
+
+ reset();
+ TIP.flushPendingComposition();
+ is(events.length, 1,
+ description + "flushPendingComposition() causing modifying composition string should cause compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "flushPendingComposition() causing modifying composition string should cause compositionupdate");
+ is(events[0].data, "FOo",
+ description + "compositionupdate caused by flushPendingComposition() should have new composition string in its data");
+ is(input.value, "FOo",
+ description + "modifying composition clause shouldn't cause modifying the focused editor");
+
+ // Committing the composition string
+ reset();
+ TIP.commitComposition();
+ is(events.length, 1,
+ description + "commitComposition() should cause compositionend but shouldn't cause compositionupdate");
+ is(events[0].type, "compositionend",
+ description + "commitComposition() should cause compositionend");
+ is(events[0].data, "FOo",
+ description + "compositionend caused by commitComposition() should have the committed string in its data");
+ is(input.value, "FOo",
+ description + "commitComposition() shouldn't cause modifying the focused editor");
+
+ // Starting new composition without a call of startComposition()
+ TIP.setPendingCompositionString("bar");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+
+ reset();
+ TIP.flushPendingComposition();
+ is(events.length, 2,
+ description + "flushPendingComposition() without a call of startComposition() should cause both compositionstart and compositionupdate");
+ is(events[0].type, "compositionstart",
+ description + "flushPendingComposition() without a call of startComposition() should cause compositionstart");
+ is(events[1].type, "compositionupdate",
+ description + "flushPendingComposition() without a call of startComposition() should cause compositionupdate after compositionstart");
+ is(events[1].data, "bar",
+ description + "compositionupdate caused by flushPendingComposition() without a call of startComposition() should have the composition string in its data");
+ is(input.value, "FOobar",
+ description + "new composition string should cause appending composition string to the focused editor");
+
+ // Canceling the composition
+ reset();
+ TIP.cancelComposition();
+ is(events.length, 2,
+ description + "cancelComposition() should cause both compositionupdate and compositionend");
+ is(events[0].type, "compositionupdate",
+ description + "cancelComposition() should cause compositionupdate");
+ is(events[0].data, "",
+ description + "compositionupdate caused by cancelComposition() should have empty string in its data");
+ is(events[1].type, "compositionend",
+ description + "cancelComposition() should cause compositionend after compositionupdate");
+ is(events[1].data, "",
+ description + "compositionend caused by cancelComposition() should have empty string in its data");
+ is(input.value, "FOo",
+ description + "canceled composition string should be removed from the focused editor");
+
+ // Starting composition explicitly and canceling it
+ reset();
+ TIP.startComposition();
+ TIP.cancelComposition();
+ is(events.length, 2,
+ description + "canceling composition immediately after startComposition() should cause compositionstart and compositionend");
+ is(events[0].type, "compositionstart",
+ description + "canceling composition immediately after startComposition() should cause compositionstart first");
+ is(events[1].type, "compositionend",
+ description + "canceling composition immediately after startComposition() should cause compositionend after compositionstart");
+ is(events[1].data, "",
+ description + "compositionend caused by canceling composition should have empty string in its data");
+ is(input.value, "FOo",
+ description + "canceling composition shouldn't modify the focused editor");
+
+ // Create composition for next test.
+ TIP.setPendingCompositionString("bar");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ is(input.value, "FOobar",
+ description + "The focused editor should have new composition string \"bar\"");
+
+ // Allow to set empty composition string
+ reset();
+ TIP.flushPendingComposition();
+ is(events.length, 1,
+ description + "making composition string empty should cause only compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "making composition string empty should cause compositionupdate");
+ is(events[0].data, "",
+ description + "compositionupdate caused by making composition string empty should have empty string in its data");
+
+ // Allow to insert new composition string without compositionend/compositionstart
+ TIP.setPendingCompositionString("buzz");
+ TIP.appendClauseToPendingComposition(4, TIP.ATTR_RAW_CLAUSE);
+
+ reset();
+ TIP.flushPendingComposition();
+ is(events.length, 1,
+ description + "modifying composition string from empty string should cause only compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "modifying composition string from empty string should cause compositionupdate");
+ is(events[0].data, "buzz",
+ description + "compositionupdate caused by modifying composition string from empty string should have new composition string in its data");
+ is(input.value, "FOobuzz",
+ description + "new composition string should be appended to the focused editor");
+
+ // Committing with different string
+ reset();
+ TIP.commitCompositionWith("bar");
+ is(events.length, 2,
+ description + "committing with different string should cause compositionupdate and compositionend");
+ is(events[0].type, "compositionupdate",
+ description + "committing with different string should cause compositionupdate first");
+ is(events[0].data, "bar",
+ description + "compositionupdate caused by committing with different string should have the committing string in its data");
+ is(events[1].type, "compositionend",
+ description + "committing with different string should cause compositionend after compositionupdate");
+ is(events[1].data, "bar",
+ description + "compositionend caused by committing with different string should have the committing string in its data");
+ is(input.value, "FOobar",
+ description + "new committed string should be appended to the focused editor");
+
+ // Appending new composition string
+ TIP.setPendingCompositionString("buzz");
+ TIP.appendClauseToPendingComposition(4, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ is(input.value, "FOobarbuzz",
+ description + "new composition string should be appended to the focused editor");
+
+ // Committing with same string
+ reset();
+ TIP.commitCompositionWith("buzz");
+ is(events.length, 1,
+ description + "committing with same string should cause only compositionend");
+ is(events[0].type, "compositionend",
+ description + "committing with same string should cause compositionend");
+ is(events[0].data, "buzz",
+ description + "compositionend caused by committing with same string should have the committing string in its data");
+ is(input.value, "FOobarbuzz",
+ description + "new committed string should be appended to the focused editor");
+
+ // Inserting commit string directly
+ reset();
+ TIP.commitCompositionWith("boo!");
+ is(events.length, 3,
+ description + "committing text directly should cause compositionstart, compositionupdate and compositionend");
+ is(events[0].type, "compositionstart",
+ description + "committing text directly should cause compositionstart first");
+ is(events[1].type, "compositionupdate",
+ description + "committing text directly should cause compositionupdate after compositionstart");
+ is(events[1].data, "boo!",
+ description + "compositionupdate caused by committing text directly should have the committing text in its data");
+ is(events[2].type, "compositionend",
+ description + "committing text directly should cause compositionend after compositionupdate");
+ is(events[2].data, "boo!",
+ description + "compositionend caused by committing text directly should have the committing text in its data");
+ is(input.value, "FOobarbuzzboo!",
+ description + "committing text directly should append the committing text to the focused editor");
+
+ window.removeEventListener("compositionstart", handler, false);
+ window.removeEventListener("compositionupdate", handler, false);
+ window.removeEventListener("compositionend", handler, false);
+}
+
+function runCompositionWithKeyEventTests()
+{
+ var description = "runCompositionWithKeyEventTests(): ";
+
+ var TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ var events;
+
+ function reset()
+ {
+ events = [];
+ }
+
+ function handler(aEvent)
+ {
+ events.push(aEvent);
+ }
+
+ window.addEventListener("compositionstart", handler, false);
+ window.addEventListener("compositionupdate", handler, false);
+ window.addEventListener("compositionend", handler, false);
+ window.addEventListener("keydown", handler, false);
+ window.addEventListener("keypress", handler, false);
+ window.addEventListener("keyup", handler, false);
+
+ input.value = "";
+ input.focus();
+
+ var printableKeyEvent = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+ var enterKeyEvent = new KeyboardEvent("", { key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ var escKeyEvent = new KeyboardEvent("", { key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
+ var convertKeyEvent = new KeyboardEvent("", { key: "Convert", code: "Convert", keyCode: KeyboardEvent.DOM_VK_CONVERT });
+ var backspaceKeyEvent = new KeyboardEvent("", { key: "Backspace", code: "Backspace", keyCode: KeyboardEvent.DOM_VK_BACK_SPACE });
+
+ Services.prefs.setBoolPref("dom.keyboardevent.dispatch_during_composition", false);
+
+ // nsITextInputProcessor.startComposition()
+ reset();
+ TIP.startComposition(printableKeyEvent);
+ is(events.length, 2,
+ description + "startComposition(printableKeyEvent) should cause keydown and compositionstart");
+ is(events[0].type, "keydown",
+ description + "startComposition(printableKeyEvent) should cause keydown");
+ is(events[1].type, "compositionstart",
+ description + "startComposition(printableKeyEvent) should cause compositionstart");
+ is(input.value, "",
+ description + "startComposition(printableKeyEvent) shouldn't modify the focused editor");
+
+ // Setting composition string "foo" as a raw clause
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+
+ reset();
+ TIP.flushPendingComposition(printableKeyEvent);
+ is(events.length, 1,
+ description + "flushPendingComposition(KeyupInternal) after startComposition() should cause compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "flushPendingComposition(KeyupInternal) after startComposition() should cause compositionupdate");
+ is(events[0].data, "foo",
+ description + "compositionupdate caused by flushPendingComposition(KeyupInternal) should have new composition string in its data");
+ is(input.value, "foo",
+ description + "modifying composition string should cause modifying the focused editor");
+
+ // Changing the raw clause to a selected clause
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_SELECTED_CLAUSE);
+
+ reset();
+ TIP.flushPendingComposition(convertKeyEvent);
+ is(events.length, 0,
+ description + "flushPendingComposition(convertKeyEvent) changing only clause information shouldn't cause compositionupdate");
+ is(input.value, "foo",
+ description + "modifying composition clause shouldn't cause modifying the focused editor");
+
+ // Separating the selected clause to two clauses
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(2, TIP.ATTR_SELECTED_CLAUSE);
+ TIP.appendClauseToPendingComposition(1, TIP.ATTR_CONVERTED_CLAUSE);
+ TIP.setCaretInPendingComposition(2);
+
+ reset();
+ TIP.flushPendingComposition(convertKeyEvent);
+ is(events.length, 0,
+ description + "flushPendingComposition(convertKeyEvent) separating a clause information shouldn't cause compositionupdate");
+ is(input.value, "foo",
+ description + "separating composition clause shouldn't cause modifying the focused editor");
+
+ // Modifying the composition string
+ TIP.setPendingCompositionString("FOo");
+ TIP.appendClauseToPendingComposition(2, TIP.ATTR_SELECTED_CLAUSE);
+ TIP.appendClauseToPendingComposition(1, TIP.ATTR_CONVERTED_CLAUSE);
+ TIP.setCaretInPendingComposition(2);
+
+ reset();
+ TIP.flushPendingComposition(convertKeyEvent);
+ is(events.length, 1,
+ description + "flushPendingComposition(convertKeyEvent) causing modifying composition string should cause compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "flushPendingComposition(convertKeyEvent) causing modifying composition string should cause compositionupdate");
+ is(events[0].data, "FOo",
+ description + "compositionupdate caused by flushPendingComposition(convertKeyEvent) should have new composition string in its data");
+ is(input.value, "FOo",
+ description + "modifying composition clause shouldn't cause modifying the focused editor");
+
+ // Committing the composition string
+ reset();
+ TIP.commitComposition(enterKeyEvent);
+ is(events.length, 2,
+ description + "commitComposition(enterKeyEvent) should cause compositionend and keyup but shoudn't cause compositionupdate");
+ is(events[0].type, "compositionend",
+ description + "commitComposition(enterKeyEvent) should cause compositionend");
+ is(events[0].data, "FOo",
+ description + "compositionend caused by commitComposition(enterKeyEvent) should have the committed string in its data");
+ is(events[1].type, "keyup",
+ description + "commitComposition(enterKeyEvent) should cause keyup");
+ is(input.value, "FOo",
+ description + "commitComposition(enterKeyEvent) shouldn't cause modifying the focused editor");
+
+ // Starting new composition without a call of startComposition()
+ TIP.setPendingCompositionString("bar");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+
+ reset();
+ TIP.flushPendingComposition(printableKeyEvent);
+ is(events.length, 3,
+ description + "flushPendingComposition(printableKeyEvent) without a call of startComposition() should cause both compositionstart and compositionupdate");
+ is(events[0].type, "keydown",
+ description + "flushPendingComposition(printableKeyEvent) without a call of startComposition() should cause keydown");
+ is(events[1].type, "compositionstart",
+ description + "flushPendingComposition(printableKeyEvent) without a call of startComposition() should cause compositionstart");
+ is(events[2].type, "compositionupdate",
+ description + "flushPendingComposition(printableKeyEvent) without a call of startComposition() should cause compositionupdate after compositionstart");
+ is(events[2].data, "bar",
+ description + "compositionupdate caused by flushPendingComposition(printableKeyEvent) without a call of startComposition() should have the composition string in its data");
+ is(input.value, "FOobar",
+ description + "new composition string should cause appending composition string to the focused editor");
+
+ // Canceling the composition
+ reset();
+ TIP.cancelComposition(escKeyEvent);
+ is(events.length, 3,
+ description + "cancelComposition(escKeyEvent) should cause both compositionupdate and compositionend");
+ is(events[0].type, "compositionupdate",
+ description + "cancelComposition(escKeyEvent) should cause compositionupdate");
+ is(events[0].data, "",
+ description + "compositionupdate caused by cancelComposition(escKeyEvent) should have empty string in its data");
+ is(events[1].type, "compositionend",
+ description + "cancelComposition(escKeyEvent) should cause compositionend after compositionupdate");
+ is(events[1].data, "",
+ description + "compositionend caused by cancelComposition(escKeyEvent) should have empty string in its data");
+ is(events[2].type, "keyup",
+ description + "cancelComposition(escKeyEvent) should cause keyup after compositionend");
+ is(input.value, "FOo",
+ description + "canceled composition string should be removed from the focused editor");
+
+ // Starting composition explicitly and canceling it
+ reset();
+ TIP.startComposition(printableKeyEvent);
+ TIP.cancelComposition(escKeyEvent);
+ is(events.length, 4,
+ description + "canceling composition immediately after startComposition() should cause keydown, compositionstart, compositionend and keyup");
+ is(events[0].type, "keydown",
+ description + "canceling composition immediately after startComposition() should cause keydown first");
+ is(events[1].type, "compositionstart",
+ description + "canceling composition immediately after startComposition() should cause compositionstart after keydown");
+ is(events[2].type, "compositionend",
+ description + "canceling composition immediately after startComposition() should cause compositionend after compositionstart");
+ is(events[2].data, "",
+ description + "compositionend caused by canceling composition should have empty string in its data");
+ is(events[3].type, "keyup",
+ description + "canceling composition immediately after startComposition() should cause keyup after compositionend");
+ is(input.value, "FOo",
+ description + "canceling composition shouldn't modify the focused editor");
+
+ // Create composition for next test.
+ TIP.setPendingCompositionString("bar");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ is(input.value, "FOobar",
+ description + "The focused editor should have new composition string \"bar\"");
+
+ // Allow to set empty composition string
+ reset();
+ TIP.flushPendingComposition(backspaceKeyEvent);
+ is(events.length, 1,
+ description + "making composition string empty should cause only compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "making composition string empty should cause compositionupdate");
+ is(events[0].data, "",
+ description + "compositionupdate caused by making composition string empty should have empty string in its data");
+
+ // Allow to insert new composition string without compositionend/compositionstart
+ TIP.setPendingCompositionString("buzz");
+ TIP.appendClauseToPendingComposition(4, TIP.ATTR_RAW_CLAUSE);
+
+ reset();
+ TIP.flushPendingComposition(printableKeyEvent);
+ is(events.length, 1,
+ description + "modifying composition string from empty string should cause only compositionupdate");
+ is(events[0].type, "compositionupdate",
+ description + "modifying composition string from empty string should cause compositionupdate");
+ is(events[0].data, "buzz",
+ description + "compositionupdate caused by modifying composition string from empty string should have new composition string in its data");
+ is(input.value, "FOobuzz",
+ description + "new composition string should be appended to the focused editor");
+
+ // Committing with different string
+ reset();
+ TIP.commitCompositionWith("bar", printableKeyEvent);
+ is(events.length, 3,
+ description + "committing with different string should cause compositionupdate and compositionend");
+ is(events[0].type, "compositionupdate",
+ description + "committing with different string should cause compositionupdate first");
+ is(events[0].data, "bar",
+ description + "compositionupdate caused by committing with different string should have the committing string in its data");
+ is(events[1].type, "compositionend",
+ description + "committing with different string should cause compositionend after compositionupdate");
+ is(events[1].data, "bar",
+ description + "compositionend caused by committing with different string should have the committing string in its data");
+ is(events[2].type, "keyup",
+ description + "committing with different string should cause keyup after compositionend");
+ is(input.value, "FOobar",
+ description + "new committed string should be appended to the focused editor");
+
+ // Appending new composition string
+ TIP.setPendingCompositionString("buzz");
+ TIP.appendClauseToPendingComposition(4, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ is(input.value, "FOobarbuzz",
+ description + "new composition string should be appended to the focused editor");
+
+ // Committing with same string
+ reset();
+ TIP.commitCompositionWith("buzz", enterKeyEvent);
+ is(events.length, 2,
+ description + "committing with same string should cause only compositionend");
+ is(events[0].type, "compositionend",
+ description + "committing with same string should cause compositionend");
+ is(events[0].data, "buzz",
+ description + "compositionend caused by committing with same string should have the committing string in its data");
+ is(events[1].type, "keyup",
+ description + "committing with same string should cause keyup after compositionend");
+ is(input.value, "FOobarbuzz",
+ description + "new committed string should be appended to the focused editor");
+
+ // Inserting commit string directly
+ reset();
+ TIP.commitCompositionWith("boo!", printableKeyEvent);
+ is(events.length, 5,
+ description + "committing text directly should cause compositionstart, compositionupdate and compositionend");
+ is(events[0].type, "keydown",
+ description + "committing text directly should cause keydown first");
+ is(events[1].type, "compositionstart",
+ description + "committing text directly should cause compositionstart after keydown");
+ is(events[2].type, "compositionupdate",
+ description + "committing text directly should cause compositionupdate after compositionstart");
+ is(events[2].data, "boo!",
+ description + "compositionupdate caused by committing text directly should have the committing text in its data");
+ is(events[3].type, "compositionend",
+ description + "committing text directly should cause compositionend after compositionupdate");
+ is(events[3].data, "boo!",
+ description + "compositionend caused by committing text directly should have the committing text in its data");
+ is(events[4].type, "keyup",
+ description + "committing text directly should cause keyup after compositionend");
+ is(input.value, "FOobarbuzzboo!",
+ description + "committing text directly should append the committing text to the focused editor");
+
+ Services.prefs.setBoolPref("dom.keyboardevent.dispatch_during_composition", true);
+
+ // Even if "dom.keyboardevent.dispatch_during_composition" is true, keypress event shouldn't be fired during composition
+ reset();
+ TIP.startComposition(printableKeyEvent);
+ is(events.length, 3,
+ description + "TIP.startComposition(printableKeyEvent) should cause keydown, compositionstart and keyup (keypress event shouldn't be fired during composition)");
+ is(events[0].type, "keydown",
+ description + "TIP.startComposition(printableKeyEvent) should cause keydown (keypress event shouldn't be fired during composition)");
+ is(events[1].type, "compositionstart",
+ description + "TIP.startComposition(printableKeyEvent) should cause compositionstart (keypress event shouldn't be fired during composition)");
+ is(events[2].type, "keyup",
+ description + "TIP.startComposition(printableKeyEvent) should cause keyup (keypress event shouldn't be fired during composition)");
+
+ // TIP.flushPendingComposition(printableKeyEvent) should cause keydown and keyup events if "dom.keyboardevent.dispatch_during_composition" is true
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+
+ reset();
+ TIP.flushPendingComposition(printableKeyEvent);
+ is(events.length, 3,
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause keydown, compositionupdate and keyup (keypress event shouldn't be fired during composition)");
+ is(events[0].type, "keydown",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause keydown (keypress event shouldn't be fired during composition)");
+ is(events[1].type, "compositionupdate",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause compositionupdate (keypress event shouldn't be fired during composition)");
+ is(events[2].type, "keyup",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause keyup (keypress event shouldn't be fired during composition)");
+
+ // TIP.commitComposition(enterKeyEvent) should cause keydown and keyup events if "dom.keyboardevent.dispatch_during_composition" is true
+ reset();
+ TIP.commitComposition(enterKeyEvent);
+ is(events.length, 3,
+ description + "TIP.commitComposition(enterKeyEvent) should cause keydown, compositionend and keyup (keypress event shouldn't be fired during composition)");
+ is(events[0].type, "keydown",
+ description + "TIP.commitComposition(enterKeyEvent) should cause keydown (keypress event shouldn't be fired during composition)");
+ is(events[1].type, "compositionend",
+ description + "TIP.commitComposition(enterKeyEvent) should cause compositionend (keypress event shouldn't be fired during composition)");
+ is(events[2].type, "keyup",
+ description + "TIP.commitComposition(enterKeyEvent) should cause keyup (keypress event shouldn't be fired during composition)");
+
+ // TIP.cancelComposition(escKeyEvent) should cause keydown and keyup events if "dom.keyboardevent.dispatch_during_composition" is true
+ TIP.startComposition();
+ reset();
+ TIP.cancelComposition(escKeyEvent);
+ is(events.length, 3,
+ description + "TIP.cancelComposition(escKeyEvent) should cause keydown, compositionend and keyup (keypress event shouldn't be fired during composition)");
+ is(events[0].type, "keydown",
+ description + "TIP.cancelComposition(escKeyEvent) should cause keydown (keypress event shouldn't be fired during composition)");
+ is(events[1].type, "compositionend",
+ description + "TIP.cancelComposition(escKeyEvent) should cause compositionend (keypress event shouldn't be fired during composition)");
+ is(events[2].type, "keyup",
+ description + "TIP.cancelComposition(escKeyEvent) should cause keyup (keypress event shouldn't be fired during composition)");
+
+ var printableKeydownEvent = new KeyboardEvent("keydown", { key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B });
+ var enterKeydownEvent = new KeyboardEvent("keydown", { key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ var escKeydownEvent = new KeyboardEvent("keydown", { key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
+
+ // TIP.startComposition(printableKeydownEvent) shouldn't cause keyup event even if "dom.keyboardevent.dispatch_during_composition" is true
+ reset();
+ TIP.startComposition(printableKeydownEvent);
+ is(events.length, 2,
+ description + "TIP.startComposition(printableKeydownEvent) should cause keydown and compositionstart (keyup event shouldn't be fired)");
+ is(events[0].type, "keydown",
+ description + "TIP.startComposition(printableKeydownEvent) should cause keydown (keyup event shouldn't be fired)");
+ is(events[1].type, "compositionstart",
+ description + "TIP.startComposition(printableKeydownEvent) should cause compositionstart (keyup event shouldn't be fired)");
+
+ // TIP.flushPendingComposition(printableKeydownEvent) shouldn't cause keyup event even if "dom.keyboardevent.dispatch_during_composition" is true
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+
+ reset();
+ TIP.flushPendingComposition(printableKeydownEvent);
+ is(events.length, 2,
+ description + "TIP.flushPendingComposition(printableKeydownEvent) should cause keydown and compositionupdate (keyup event shouldn't be fired)");
+ is(events[0].type, "keydown",
+ description + "TIP.flushPendingComposition(printableKeydownEvent) should cause keydown (keyup event shouldn't be fired)");
+ is(events[1].type, "compositionupdate",
+ description + "TIP.flushPendingComposition(printableKeydownEvent) should cause compositionupdate (keyup event shouldn't be fired)");
+
+ // TIP.commitComposition(enterKeydownEvent) shouldn't cause keyup event even if "dom.keyboardevent.dispatch_during_composition" is true
+ reset();
+ TIP.commitComposition(enterKeydownEvent);
+ is(events.length, 2,
+ description + "TIP.commitComposition(enterKeydownEvent) should cause keydown and compositionend (keyup event shouldn't be fired)");
+ is(events[0].type, "keydown",
+ description + "TIP.commitComposition(enterKeydownEvent) should cause keydown (keyup event shouldn't be fired)");
+ is(events[1].type, "compositionend",
+ description + "TIP.commitComposition(enterKeydownEvent) should cause compositionend (keyup event shouldn't be fired)");
+
+ // TIP.cancelComposition(escKeydownEvent) shouldn't cause keyup event even if "dom.keyboardevent.dispatch_during_composition" is true
+ TIP.startComposition();
+ reset();
+ TIP.cancelComposition(escKeydownEvent);
+ is(events.length, 2,
+ description + "TIP.cancelComposition(escKeydownEvent) should cause keydown and compositionend (keyup event shouldn't be fired)");
+ is(events[0].type, "keydown",
+ description + "TIP.cancelComposition(escKeydownEvent) should cause keydown (keyup event shouldn't be fired)");
+ is(events[1].type, "compositionend",
+ description + "TIP.cancelComposition(escKeydownEvent) should cause compositionend (keyup event shouldn't be fired)");
+
+ Services.prefs.clearUserPref("dom.keyboardevent.dispatch_during_composition");
+
+ window.removeEventListener("compositionstart", handler, false);
+ window.removeEventListener("compositionupdate", handler, false);
+ window.removeEventListener("compositionend", handler, false);
+ window.removeEventListener("keydown", handler, false);
+ window.removeEventListener("keypress", handler, false);
+ window.removeEventListener("keyup", handler, false);
+}
+
+function runConsumingKeydownBeforeCompositionTests()
+{
+ var description = "runConsumingKeydownBeforeCompositionTests(): ";
+
+ var TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ var events;
+
+ function reset()
+ {
+ events = [];
+ }
+
+ function handler(aEvent)
+ {
+ events.push(aEvent);
+ if (aEvent.type == "keydown") {
+ aEvent.preventDefault();
+ }
+ }
+
+ window.addEventListener("compositionstart", handler, false);
+ window.addEventListener("compositionupdate", handler, false);
+ window.addEventListener("compositionend", handler, false);
+ window.addEventListener("keydown", handler, false);
+ window.addEventListener("keypress", handler, false);
+ window.addEventListener("keyup", handler, false);
+
+ input.value = "";
+ input.focus();
+
+ var printableKeyEvent = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+ var enterKeyEvent = new KeyboardEvent("", { key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ var escKeyEvent = new KeyboardEvent("", { key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
+
+ Services.prefs.setBoolPref("dom.keyboardevent.dispatch_during_composition", false);
+
+ // If keydown before compositionstart is consumed, composition shouldn't be started.
+ reset();
+ ok(!TIP.startComposition(printableKeyEvent),
+ description + "TIP.startComposition(printableKeyEvent) should return false because it's keydown is consumed");
+ is(events.length, 2,
+ description + "TIP.startComposition(printableKeyEvent) should cause only keydown and keyup events");
+ is(events[0].type, "keydown",
+ description + "TIP.startComposition(printableKeyEvent) should cause keydown event first");
+ is(events[1].type, "keyup",
+ description + "TIP.startComposition(printableKeyEvent) should cause keyup event after keydown");
+ ok(!TIP.hasComposition,
+ description + "TIP.startComposition(printableKeyEvent) shouldn't cause composition");
+ is(input.value, "",
+ description + "TIP.startComposition(printableKeyEvent) shouldn't cause inserting text");
+
+ // If keydown before compositionstart caused by flushPendingComposition(printableKeyEvent) is consumed, composition shouldn't be started.
+ reset();
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ ok(!TIP.flushPendingComposition(printableKeyEvent),
+ description + "TIP.flushPendingComposition(printableKeyEvent) should return false because it's keydown is consumed");
+ is(events.length, 2,
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause only keydown and keyup events");
+ is(events[0].type, "keydown",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause keydown event first");
+ is(events[1].type, "keyup",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause keyup event after keydown");
+ ok(!TIP.hasComposition,
+ description + "TIP.flushPendingComposition(printableKeyEvent) shouldn't cause composition");
+ is(input.value, "",
+ description + "TIP.flushPendingComposition(printableKeyEvent) shouldn't cause inserting text");
+
+ // If keydown before compositionstart is consumed, composition shouldn't be started.
+ reset();
+ ok(!TIP.commitCompositionWith("foo", printableKeyEvent),
+ description + "TIP.commitCompositionWith(\"foo\", printableKeyEvent) should return false because it's keydown is consumed");
+ is(events.length, 2,
+ description + "TIP.commitCompositionWith(\"foo\", printableKeyEvent) should cause only keydown and keyup events");
+ is(events[0].type, "keydown",
+ description + "TIP.commitCompositionWith(\"foo\", printableKeyEvent) should cause keydown event first");
+ is(events[1].type, "keyup",
+ description + "TIP.commitCompositionWith(\"foo\", printableKeyEvent) should cause keyup event after keydown");
+ ok(!TIP.hasComposition,
+ description + "TIP.commitCompositionWith(\"foo\", printableKeyEvent) shouldn't cause composition");
+ is(input.value, "",
+ description + "TIP.commitCompositionWith(\"foo\", printableKeyEvent) shouldn't cause inserting text");
+
+ Services.prefs.setBoolPref("dom.keyboardevent.dispatch_during_composition", true);
+
+ // If composition is already started, TIP.flushPendingComposition(printableKeyEvent) shouldn't be canceled.
+ TIP.startComposition();
+ ok(TIP.hasComposition,
+ description + "Before TIP.flushPendingComposition(printableKeyEvent), composition should've been created");
+ reset();
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ ok(TIP.flushPendingComposition(printableKeyEvent),
+ description + "TIP.flushPendingComposition(printableKeyEvent) should return true even if preceding keydown is consumed because there was a composition already");
+ is(events.length, 3,
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause only keydown and keyup events");
+ is(events[0].type, "keydown",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause keydown event first");
+ is(events[1].type, "compositionupdate",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause compositionupdate event after keydown");
+ is(events[2].type, "keyup",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause keyup event after compositionupdate");
+ ok(TIP.hasComposition,
+ description + "TIP.flushPendingComposition(printableKeyEvent) shouldn't cause canceling composition");
+ is(input.value, "foo",
+ description + "TIP.flushPendingComposition(printableKeyEvent) should cause inserting text even if preceding keydown is consumed because there was a composition already");
+
+ // If composition is already started, TIP.commitComposition(enterKeyEvent) shouldn't be canceled.
+ reset();
+ TIP.commitComposition(enterKeyEvent);
+ is(events.length, 3,
+ description + "TIP.commitComposition(enterKeyEvent) should cause keydown, compositionend and keyup events");
+ is(events[0].type, "keydown",
+ description + "TIP.commitComposition(enterKeyEvent) should cause keydown event first");
+ is(events[1].type, "compositionend",
+ description + "TIP.commitComposition(enterKeyEvent) should cause compositionend event after keydown");
+ is(events[2].type, "keyup",
+ description + "TIP.commitComposition(enterKeyEvent) should cause keyup event after compositionend");
+ ok(!TIP.hasComposition,
+ description + "TIP.commitComposition(enterKeyEvent) should cause committing composition even if preceding keydown is consumed because there was a composition already");
+ is(input.value, "foo",
+ description + "TIP.commitComposition(enterKeyEvent) should commit composition even if preceding keydown is consumed because there was a composition already");
+
+ // cancelComposition() should work even if preceding keydown event is consumed.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ ok(TIP.hasComposition,
+ description + "Before TIP.cancelComposition(escKeyEvent), composition should've been created");
+ is(input.value, "foo",
+ description + "Before TIP.cancelComposition(escKeyEvent) should have composition string");
+ reset();
+ TIP.cancelComposition(escKeyEvent);
+ is(events.length, 4,
+ description + "TIP.cancelComposition(escKeyEvent) should cause keydown, compositionupdate, compositionend and keyup events even if preceding keydown is consumed because there was a composition already");
+ is(events[0].type, "keydown",
+ description + "TIP.cancelComposition(escKeyEvent) should cause keydown event first");
+ is(events[1].type, "compositionupdate",
+ description + "TIP.cancelComposition(escKeyEvent) should cause compositionupdate event after keydown");
+ is(events[2].type, "compositionend",
+ description + "TIP.cancelComposition(escKeyEvent) should cause compositionend event after compositionupdate");
+ is(events[3].type, "keyup",
+ description + "TIP.cancelComposition(escKeyEvent) should cause keyup event after compositionend");
+ ok(!TIP.hasComposition,
+ description + "TIP.cancelComposition(escKeyEvent) should cause canceling composition even if preceding keydown is consumed because there was a composition already");
+ is(input.value, "",
+ description + "TIP.cancelComposition(escKeyEvent) should cancel composition even if preceding keydown is consumed because there was a composition already");
+
+ Services.prefs.clearUserPref("dom.keyboardevent.dispatch_during_composition");
+
+ window.removeEventListener("compositionstart", handler, false);
+ window.removeEventListener("compositionupdate", handler, false);
+ window.removeEventListener("compositionend", handler, false);
+ window.removeEventListener("keydown", handler, false);
+ window.removeEventListener("keypress", handler, false);
+ window.removeEventListener("keyup", handler, false);
+}
+
+function runKeyTests()
+{
+ var description = "runKeyTests(): ";
+ const kModifiers =
+ [ "Alt", "AltGraph", "CapsLock", "Control", "Fn", "FnLock", "Meta", "NumLock",
+ "ScrollLock", "Shift", "Symbol", "SymbolLock", "OS" ];
+
+ var TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ var events;
+ var doPreventDefaults;
+
+ function reset()
+ {
+ events = [];
+ doPreventDefaults = [];
+ }
+
+ function handler(aEvent)
+ {
+ events.push(aEvent);
+ if (doPreventDefaults.includes(aEvent.type)) {
+ aEvent.preventDefault();
+ }
+ }
+
+ function checkKeyAttrs(aMethodDescription, aEvent, aExpectedData)
+ {
+ var desc = description + aMethodDescription + ", type=\"" + aEvent.type + "\", key=\"" + aEvent.key + "\", code=\"" + aEvent.code + "\": ";
+ var defaultValues = {
+ key: "Unidentified", code: "", keyCode: 0, charCode: 0,
+ location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD, repeat: false, isComposing: false,
+ shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
+ defaultPrevented: false
+ };
+ function expectedValue(aAttr)
+ {
+ return aExpectedData[aAttr] !== undefined ? aExpectedData[aAttr] : defaultValues[aAttr];
+ }
+ is(aEvent.type, aExpectedData.type,
+ desc + " should cause keydown event");
+ if (aEvent.type != aExpectedData.type) {
+ return;
+ }
+ is(aEvent.defaultPrevented, expectedValue("defaultPrevented"),
+ desc + ".defaultPrevented is wrong");
+ is(aEvent.key, expectedValue("key"),
+ desc + ".key is wrong");
+ is(aEvent.code, expectedValue("code"),
+ desc + ".code is wrong");
+ is(aEvent.location, expectedValue("location"),
+ desc + ".location is wrong");
+ is(aEvent.repeat, expectedValue("repeat"),
+ desc + ".repeat is wrong");
+ is(aEvent.isComposing, expectedValue("isComposing"),
+ desc + ".isComposing is wrong");
+ is(aEvent.keyCode, expectedValue("keyCode"),
+ desc + ".keyCode is wrong");
+ is(aEvent.charCode, expectedValue("charCode"),
+ desc + ".charCode is wrong");
+ is(aEvent.shiftKey, expectedValue("shiftKey"),
+ desc + ".shiftKey is wrong");
+ is(aEvent.ctrlKey, expectedValue("ctrlKey"),
+ desc + ".ctrlKey is wrong");
+ is(aEvent.altKey, expectedValue("altKey"),
+ desc + ".altKey is wrong");
+ is(aEvent.metaKey, expectedValue("metaKey"),
+ desc + ".metaKey is wrong");
+ for (var i = 0; i < kModifiers.length; i++) {
+ is(aEvent.getModifierState(kModifiers[i]), aExpectedData[kModifiers[i]] !== undefined ? aExpectedData[kModifiers[i]] : false,
+ desc + ".getModifierState(\"" + kModifiers[i] + "\") is wrong");
+ }
+ }
+
+ window.addEventListener("keydown", handler, false);
+ window.addEventListener("keypress", handler, false);
+ window.addEventListener("keyup", handler, false);
+
+ input.value = "";
+ input.focus();
+
+
+ // Printable key test:
+ // Emulates pressing 'a' key.
+ var keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+
+ reset();
+ var doDefaultKeydown = TIP.keydown(keyA);
+
+ is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
+ description + "TIP.keydown(keyA) should return 0x02 because the keypress event should be consumed by the input element");
+ is(events.length, 2,
+ description + "TIP.keydown(keyA) should cause keydown and keypress event");
+ checkKeyAttrs("TIP.keydown(keyA)", events[0],
+ { type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0 });
+ checkKeyAttrs("TIP.keydown(keyA)", events[1],
+ { type: "keypress", key: "a", code: "KeyA", keyCode: 0, charCode: "a".charCodeAt(0), defaultPrevented: true });
+ is(input.value, "a",
+ description + "input.value should be \"a\" which is inputted by TIP.keydown(keyA)");
+
+ // Emulates releasing 'a' key.
+ reset();
+ var doDefaultKeyup = TIP.keyup(keyA);
+ ok(doDefaultKeyup,
+ description + "TIP.keyup(keyA) should return true");
+ is(events.length, 1,
+ description + "TIP.keyup(keyA) should cause keyup event");
+ checkKeyAttrs("TIP.keyup(keyA)", events[0],
+ { type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0 });
+ is(input.value, "a",
+ description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
+
+
+ // Non-printable key test:
+ // Emulates pressing Enter key.
+ var keyEnter = new KeyboardEvent("", { key: "Enter", code: "Enter" });
+
+ reset();
+ doDefaultKeydown = TIP.keydown(keyEnter);
+
+ is(doDefaultKeydown, 0,
+ description + "TIP.keydown(keyEnter) should return 0");
+ is(events.length, 2,
+ description + "TIP.keydown(keyEnter) should cause keydown and keypress event");
+ checkKeyAttrs("TIP.keydown(keyEnter)", events[0],
+ { type: "keydown", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ checkKeyAttrs("TIP.keydown(keyEnter)", events[1],
+ { type: "keypress", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ is(input.value, "a",
+ description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
+
+ // Emulates releasing Enter key.
+ reset();
+ doDefaultKeyup = TIP.keyup(keyEnter);
+ ok(doDefaultKeyup,
+ description + "TIP.keyup(keyEnter) should return true");
+ is(events.length, 1,
+ description + "TIP.keyup(keyEnter) should cause keyup event");
+ checkKeyAttrs("TIP.keyup(keyEnter)", events[0],
+ { type: "keyup", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ is(input.value, "a",
+ description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
+
+
+ // KEY_DEFAULT_PREVENTED should cause defaultPrevented = true and not cause keypress event
+ var keyB = new KeyboardEvent("", { key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B });
+
+ reset();
+ doDefaultKeydown = TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED);
+ doDefaultKeyup = TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED);
+
+ is(doDefaultKeydown, TIP.KEYDOWN_IS_CONSUMED,
+ description + "TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) should return 0x01 because it's marked as consumed at dispatching the event");
+ ok(!doDefaultKeyup,
+ description + "TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED) should return false because it's marked as consumed at dispatching the event");
+ is(events.length, 2,
+ description + "TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) and TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED) should cause keydown and keyup event");
+ checkKeyAttrs("TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) and TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED)", events[0],
+ { type: "keydown", key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B, defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) and TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED)", events[1],
+ { type: "keyup", key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B, defaultPrevented: true });
+ is(input.value, "a",
+ description + "input.value shouldn't be modified by default prevented key events");
+
+ // Assume that KeyX causes inputting text "abc"
+ input.value = "";
+ var keyABC = new KeyboardEvent("", { key: "abc", code: "KeyX", keyCode: KeyboardEvent.DOM_VK_A });
+
+ reset();
+ doDefaultKeydown = TIP.keydown(keyABC);
+ doDefaultKeyup = TIP.keyup(keyABC);
+
+ is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
+ description + "TIP.keydown(keyABC) should return false because the keypress events should be consumed by the input element");
+ ok(doDefaultKeyup,
+ description + "TIP.keyup(keyABC) should return true");
+ is(events.length, 5,
+ description + "TIP.keydown(keyABC) and TIP.keyup(keyABC) should cause keydown, keypress, keypress, keypress and keyup event");
+ checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[0],
+ { type: "keydown", key: "abc", code: "KeyX", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
+ checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[1],
+ { type: "keypress", key: "abc".charAt(0), code: "KeyX", keyCode: 0, charCode: "abc".charCodeAt(0), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[2],
+ { type: "keypress", key: "abc".charAt(1), code: "KeyX", keyCode: 0, charCode: "abc".charCodeAt(1), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[3],
+ { type: "keypress", key: "abc".charAt(2), code: "KeyX", keyCode: 0, charCode: "abc".charCodeAt(2), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[4],
+ { type: "keyup", key: "abc", code: "KeyX", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
+ is(input.value, "abc",
+ description + "input.value should be \"abc\"");
+
+ // If KEY_FORCE_PRINTABLE_KEY is specified, registered key names can be a printable key which inputs the specified value.
+ input.value = "";
+ var keyEnterPrintable = new KeyboardEvent("", { key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+
+ reset();
+ doDefaultKeydown = TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY);
+ doDefaultKeyup = TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY);
+
+ is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
+ description + "TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should return 0x02 because the keypress events should be consumed by the input element");
+ ok(doDefaultKeyup,
+ description + "TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should return true");
+ is(events.length, 7,
+ description + "TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should cause keydown, keypress, keypress, keypress, keypress, keypress and keyup event");
+ checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[0],
+ { type: "keydown", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN, charCode: 0, defaultPrevented: false });
+ checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[1],
+ { type: "keypress", key: "Enter".charAt(0), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(0), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[2],
+ { type: "keypress", key: "Enter".charAt(1), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(1), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[3],
+ { type: "keypress", key: "Enter".charAt(2), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(2), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[4],
+ { type: "keypress", key: "Enter".charAt(3), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(3), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[5],
+ { type: "keypress", key: "Enter".charAt(4), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(4), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[6],
+ { type: "keyup", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN, charCode: 0, defaultPrevented: false });
+ is(input.value, "Enter",
+ description + "input.value should be \"Enter\"");
+
+ // modifiers should be ignored.
+ var keyWithModifiers = new KeyboardEvent("", { key: "Escape", code: "Escape", shiftKey: true, ctrlKey: true, altKey: true, metaKey: true });
+
+ reset();
+ doDefaultKeydown = TIP.keydown(keyWithModifiers);
+ doDefaultKeyup = TIP.keyup(keyWithModifiers);
+
+ is(doDefaultKeydown, 0,
+ description + "TIP.keydown(keyWithModifiers) should return 0");
+ ok(doDefaultKeyup,
+ description + "TIP.keyup(keyWithModifiers) should return true");
+ is(events.length, 3,
+ description + "TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers) should cause keydown, keypress and keyup event");
+ checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[0],
+ { type: "keydown", key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
+ checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[1],
+ { type: "keypress", key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
+ checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[2],
+ { type: "keyup", key: "Escape", code: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE });
+ is(input.value, "Enter",
+ description + "input.value should stay \"Enter\" which was inputted by TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)");
+
+ // Call preventDefault() at keydown
+ input.value = "";
+ reset();
+ doPreventDefaults = [ "keydown" ];
+ doDefaultKeydown = TIP.keydown(keyA);
+ doDefaultKeyup = TIP.keyup(keyA);
+
+ is(doDefaultKeydown, TIP.KEYDOWN_IS_CONSUMED,
+ description + "TIP.keydown(keyA) should return 0x01 because keydown event's preventDefault should be called");
+ ok(doDefaultKeyup,
+ description + "TIP.keyup(keyA) should return true");
+ is(events.length, 2,
+ description + "TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keydown should cause keydown and keyup event");
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keydown", events[0],
+ { type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keydown", events[1],
+ { type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, defaultPrevented: false });
+ is(input.value, "",
+ description + "input.value shouldn't be modified by TIP.keyup(keyA) if the keydown event is consumed");
+
+ // Call preventDefault() at keypress
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ doDefaultKeydown = TIP.keydown(keyA);
+ doDefaultKeyup = TIP.keyup(keyA);
+
+ is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
+ description + "TIP.keydown(keyA) should return 0x02 because keypress event's preventDefault should be called");
+ ok(doDefaultKeyup,
+ description + "TIP.keyup(keyA) should return true");
+ is(events.length, 3,
+ description + "TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress should cause keydown, keypress and keyup event");
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress", events[0],
+ { type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress", events[1],
+ { type: "keypress", key: "a", code: "KeyA", keyCode: 0, charCode: "a".charCodeAt(0), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress", events[2],
+ { type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
+ is(input.value, "",
+ description + "input.value shouldn't be modified by TIP.keyup(keyA) if the keypress event is consumed");
+
+ // Call preventDefault() at keyup
+ input.value = "";
+ reset();
+ doPreventDefaults = [ "keyup" ];
+ doDefaultKeydown = TIP.keydown(keyA);
+ doDefaultKeyup = TIP.keyup(keyA);
+
+ is(doDefaultKeydown, TIP.KEYPRESS_IS_CONSUMED,
+ description + "TIP.keydown(keyA) should return 0x02 because the key event should be consumed by the input element");
+ ok(!doDefaultKeyup,
+ description + "TIP.keyup(keyA) should return false because keyup event's preventDefault should be called");
+ is(events.length, 3,
+ description + "TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup should cause keydown, keypress and keyup event");
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup", events[0],
+ { type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup", events[1],
+ { type: "keypress", key: "a", code: "KeyA", keyCode: 0, charCode: "a".charCodeAt(0), defaultPrevented: true });
+ checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup", events[2],
+ { type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: true });
+ is(input.value, "a",
+ description + "input.value should be \"a\" by TIP.keyup(keyA) even if the keyup event is consumed");
+
+ // key events during composition
+ try {
+ Services.prefs.setBoolPref("dom.keyboardevent.dispatch_during_composition", false);
+
+ ok(TIP.startComposition(), "TIP.startComposition() should start composition");
+
+ input.value = "";
+ reset();
+ TIP.keydown(keyA);
+ is(events.length, 0,
+ description + "TIP.keydown(keyA) shouldn't cause key events during composition if it's disabled by the pref");
+ reset();
+ TIP.keyup(keyA);
+ is(events.length, 0,
+ description + "TIP.keyup(keyA) shouldn't cause key events during composition if it's disabled by the pref");
+
+ Services.prefs.setBoolPref("dom.keyboardevent.dispatch_during_composition", true);
+ reset();
+ TIP.keydown(keyA);
+ is(events.length, 1,
+ description + "TIP.keydown(keyA) should cause keydown event even composition if it's enabled by the pref");
+ checkKeyAttrs("TIP.keydown(keyA) during composition", events[0],
+ { type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, isComposing: true });
+ reset();
+ TIP.keyup(keyA);
+ is(events.length, 1,
+ description + "TIP.keyup(keyA) should cause keyup event even composition if it's enabled by the pref");
+ checkKeyAttrs("TIP.keyup(keyA) during composition", events[0],
+ { type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, isComposing: true });
+
+ } finally {
+ TIP.cancelComposition();
+ Services.prefs.clearUserPref("dom.keyboardevent.dispatch_during_composition");
+ }
+
+ // Test .location computation
+ const kCodeToLocation = [
+ { code: "BracketLeft", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "BracketRight", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Comma", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit0", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit1", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit2", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit3", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit4", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit5", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit6", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit7", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit8", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Digit9", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Equal", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Minus", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Period", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Slash", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "AltLeft", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ { code: "AltRight", location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ { code: "CapsLock", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "ContextMenu", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "ControlLeft", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ { code: "ControlRight", location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ { code: "Enter", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "OSLeft", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ { code: "OSRight", location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ { code: "ShiftLeft", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
+ { code: "ShiftRight", location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
+ { code: "Space", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Tab", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "ArrowDown", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "ArrowLeft", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "ArrowRight", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "ArrowUp", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "NumLock", location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
+ { code: "Numpad0", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad1", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad2", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad3", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad4", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad5", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad6", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad7", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad8", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "Numpad9", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadAdd", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadBackspace", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadClear", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadClearEntry", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadComma", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadDecimal", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadDivide", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadEnter", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadEqual", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadMemoryAdd", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadMemoryClear", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadMemoryRecall", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadMemoryStore", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadMemorySubtract", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadMultiply", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadParenLeft", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadParenRight", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ { code: "NumpadSubtract", location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
+ ];
+ for (var i = 0; i < kCodeToLocation.length; i++) {
+ var keyEvent = new KeyboardEvent("", { code: kCodeToLocation[i].code });
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ // If the location isn't initialized or initialized with 0, it should be computed from the code value.
+ TIP.keydown(keyEvent);
+ TIP.keyup(keyEvent);
+ var longDesc = description + "testing computation of .location of \"" + kCodeToLocation[i].code + "\", ";
+ is(events.length, 3,
+ longDesc + "keydown, keypress and keyup events should be fired");
+ for (var j = 0; j < events.length; j++) {
+ is(events[j].location, kCodeToLocation[i].location,
+ longDesc + " type=\"" + events[j].type + "\", location value is wrong");
+ }
+ // However, if KEY_KEEP_KEY_LOCATION_STANDARD is specified, .location value should be kept as DOM_KEY_LOCATION_STANDARD (0).
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+ TIP.keyup(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+ var longDesc = description + "testing if .location is forcibly set to DOM_KEY_LOCATION_STANDARD, ";
+ is(events.length, 3,
+ longDesc + "keydown, keypress and keyup events should be fired");
+ for (var j = 0; j < events.length; j++) {
+ is(events[j].location, KeyboardEvent.DOM_KEY_LOCATION_STANDARD,
+ longDesc + " type=\"" + events[j].type + "\", location value is not 0");
+ }
+ // If .location is initialized with non-zero value, the value shouldn't be computed again.
+ var keyEventWithLocation = new KeyboardEvent("", { code: kCodeToLocation[i].code, location: 0xFF });
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(keyEventWithLocation);
+ TIP.keyup(keyEventWithLocation);
+ longDesc = description + "testing if .location is not computed for \"" + kCodeToLocation[i].location + "\", ";
+ is(events.length, 3,
+ longDesc + "keydown, keypress and keyup events should be fired");
+ for (var j = 0; j < events.length; j++) {
+ is(events[j].location, 0xFF,
+ longDesc + " type=\"" + events[j].type + "\", location shouldn't be computed if it's initialized with non-zero value");
+ }
+ }
+
+ // Test .keyCode value computation
+ const kKeyToKeyCode = [
+ { key: "Cancel", keyCode: KeyboardEvent.DOM_VK_CANCEL },
+ { key: "Help", keyCode: KeyboardEvent.DOM_VK_HELP },
+ { key: "Backspace", keyCode: KeyboardEvent.DOM_VK_BACK_SPACE },
+ { key: "Tab", keyCode: KeyboardEvent.DOM_VK_TAB },
+ { key: "Clear", keyCode: KeyboardEvent.DOM_VK_CLEAR },
+ { key: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN },
+ { key: "Shift", keyCode: KeyboardEvent.DOM_VK_SHIFT, isModifier: true },
+ { key: "Control", keyCode: KeyboardEvent.DOM_VK_CONTROL, isModifier: true },
+ { key: "Alt", keyCode: KeyboardEvent.DOM_VK_ALT, isModifier: true },
+ { key: "Pause", keyCode: KeyboardEvent.DOM_VK_PAUSE },
+ { key: "CapsLock", keyCode: KeyboardEvent.DOM_VK_CAPS_LOCK, isModifier: true, isLockableModifier: true },
+ { key: "Hiragana", keyCode: KeyboardEvent.DOM_VK_KANA },
+ { key: "Katakana", keyCode: KeyboardEvent.DOM_VK_KANA },
+ { key: "HiraganaKatakana", keyCode: KeyboardEvent.DOM_VK_KANA },
+ { key: "KanaMode", keyCode: KeyboardEvent.DOM_VK_KANA },
+ { key: "HangulMode", keyCode: KeyboardEvent.DOM_VK_HANGUL },
+ { key: "Eisu", keyCode: KeyboardEvent.DOM_VK_EISU },
+ { key: "JunjaMode", keyCode: KeyboardEvent.DOM_VK_JUNJA },
+ { key: "FinalMode", keyCode: KeyboardEvent.DOM_VK_FINAL },
+ { key: "HanjaMode", keyCode: KeyboardEvent.DOM_VK_HANJA },
+ { key: "KanjiMode", keyCode: KeyboardEvent.DOM_VK_KANJI },
+ { key: "Escape", keyCode: KeyboardEvent.DOM_VK_ESCAPE },
+ { key: "Convert", keyCode: KeyboardEvent.DOM_VK_CONVERT },
+ { key: "NonConvert", keyCode: KeyboardEvent.DOM_VK_NONCONVERT },
+ { key: "Accept", keyCode: KeyboardEvent.DOM_VK_ACCEPT },
+ { key: "ModeChange", keyCode: KeyboardEvent.DOM_VK_MODECHANGE },
+ { key: "PageUp", keyCode: KeyboardEvent.DOM_VK_PAGE_UP },
+ { key: "PageDown", keyCode: KeyboardEvent.DOM_VK_PAGE_DOWN },
+ { key: "End", keyCode: KeyboardEvent.DOM_VK_END },
+ { key: "Home", keyCode: KeyboardEvent.DOM_VK_HOME },
+ { key: "ArrowLeft", keyCode: KeyboardEvent.DOM_VK_LEFT },
+ { key: "ArrowUp", keyCode: KeyboardEvent.DOM_VK_UP },
+ { key: "ArrowRight", keyCode: KeyboardEvent.DOM_VK_RIGHT },
+ { key: "ArrowDown", keyCode: KeyboardEvent.DOM_VK_DOWN },
+ { key: "Select", keyCode: KeyboardEvent.DOM_VK_SELECT },
+ { key: "Print", keyCode: KeyboardEvent.DOM_VK_PRINT },
+ { key: "Execute", keyCode: KeyboardEvent.DOM_VK_EXECUTE },
+ { key: "PrintScreen", keyCode: KeyboardEvent.DOM_VK_PRINTSCREEN },
+ { key: "Insert", keyCode: KeyboardEvent.DOM_VK_INSERT },
+ { key: "Delete", keyCode: KeyboardEvent.DOM_VK_DELETE },
+ { key: "OS", keyCode: KeyboardEvent.DOM_VK_WIN, isModifier: true },
+ { key: "ContextMenu", keyCode: KeyboardEvent.DOM_VK_CONTEXT_MENU },
+ { key: "F1", keyCode: KeyboardEvent.DOM_VK_F1 },
+ { key: "F2", keyCode: KeyboardEvent.DOM_VK_F2 },
+ { key: "F3", keyCode: KeyboardEvent.DOM_VK_F3 },
+ { key: "F4", keyCode: KeyboardEvent.DOM_VK_F4 },
+ { key: "F5", keyCode: KeyboardEvent.DOM_VK_F5 },
+ { key: "F6", keyCode: KeyboardEvent.DOM_VK_F6 },
+ { key: "F7", keyCode: KeyboardEvent.DOM_VK_F7 },
+ { key: "F8", keyCode: KeyboardEvent.DOM_VK_F8 },
+ { key: "F9", keyCode: KeyboardEvent.DOM_VK_F9 },
+ { key: "F10", keyCode: KeyboardEvent.DOM_VK_F10 },
+ { key: "F11", keyCode: KeyboardEvent.DOM_VK_F11 },
+ { key: "F12", keyCode: KeyboardEvent.DOM_VK_F12 },
+ { key: "F13", keyCode: KeyboardEvent.DOM_VK_F13 },
+ { key: "F14", keyCode: KeyboardEvent.DOM_VK_F14 },
+ { key: "F15", keyCode: KeyboardEvent.DOM_VK_F15 },
+ { key: "F16", keyCode: KeyboardEvent.DOM_VK_F16 },
+ { key: "F17", keyCode: KeyboardEvent.DOM_VK_F17 },
+ { key: "F18", keyCode: KeyboardEvent.DOM_VK_F18 },
+ { key: "F19", keyCode: KeyboardEvent.DOM_VK_F19 },
+ { key: "F20", keyCode: KeyboardEvent.DOM_VK_F20 },
+ { key: "F21", keyCode: KeyboardEvent.DOM_VK_F21 },
+ { key: "F22", keyCode: KeyboardEvent.DOM_VK_F22 },
+ { key: "F23", keyCode: KeyboardEvent.DOM_VK_F23 },
+ { key: "F24", keyCode: KeyboardEvent.DOM_VK_F24 },
+ { key: "NumLock", keyCode: KeyboardEvent.DOM_VK_NUM_LOCK, isModifier: true, isLockableModifier: true },
+ { key: "ScrollLock", keyCode: KeyboardEvent.DOM_VK_SCROLL_LOCK, isModifier: true, isLockableModifier: true },
+ { key: "AudioVolumeMute", keyCode: KeyboardEvent.DOM_VK_VOLUME_MUTE },
+ { key: "AudioVolumeDown", keyCode: KeyboardEvent.DOM_VK_VOLUME_DOWN },
+ { key: "AudioVolumeUp", keyCode: KeyboardEvent.DOM_VK_VOLUME_UP },
+ { key: "Meta", keyCode: KeyboardEvent.DOM_VK_META, isModifier: true },
+ { key: "AltGraph", keyCode: KeyboardEvent.DOM_VK_ALTGR, isModifier: true },
+ { key: "Attn", keyCode: KeyboardEvent.DOM_VK_ATTN },
+ { key: "CrSel", keyCode: KeyboardEvent.DOM_VK_CRSEL },
+ { key: "ExSel", keyCode: KeyboardEvent.DOM_VK_EXSEL },
+ { key: "EraseEof", keyCode: KeyboardEvent.DOM_VK_EREOF },
+ { key: "Play", keyCode: KeyboardEvent.DOM_VK_PLAY },
+ { key: "ZoomToggle", keyCode: KeyboardEvent.DOM_VK_ZOOM },
+ { key: "ZoomIn", keyCode: KeyboardEvent.DOM_VK_ZOOM },
+ { key: "ZoomOut", keyCode: KeyboardEvent.DOM_VK_ZOOM },
+ { key: "Unidentified", keyCode: 0 },
+ { key: "a", keyCode: 0, isPrintable: true },
+ { key: "A", keyCode: 0, isPrintable: true },
+ { key: " ", keyCode: 0, isPrintable: true },
+ { key: "", keyCode: 0, isPrintable: true },
+ ];
+
+ for (var i = 0; i < kKeyToKeyCode.length; i++) {
+ var keyEvent = new KeyboardEvent("", { key: kKeyToKeyCode[i].key });
+ var causeKeypress = !kKeyToKeyCode[i].isModifier;
+ var baseFlags = kKeyToKeyCode[i].isPrintable ? 0 : TIP.KEY_NON_PRINTABLE_KEY;
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ // If the keyCode isn't initialized or initialized with 0, it should be computed from the key value only when it's a printable key.
+ TIP.keydown(keyEvent, baseFlags);
+ TIP.keyup(keyEvent, baseFlags);
+ var longDesc = description + "testing computation of .keyCode of \"" + kKeyToKeyCode[i].key + "\", ";
+ is(events.length, causeKeypress ? 3 : 2,
+ longDesc + "keydown" + (causeKeypress ? ", keypress" : "") + " and keyup events should be fired");
+ for (var j = 0; j < events.length; j++) {
+ is(events[j].keyCode, events[j].type == "keypress" && kKeyToKeyCode[i].isPrintable ? 0 : kKeyToKeyCode[i].keyCode,
+ longDesc + " type=\"" + events[j].type + "\", keyCode value is wrong");
+ }
+ // However, if KEY_KEEP_KEYCODE_ZERO is specified, .keyCode value should be kept as 0.
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO | baseFlags);
+ TIP.keyup(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO | baseFlags);
+ var longDesc = description + "testing if .keyCode is forcibly set to KEY_KEEP_KEYCODE_ZERO, ";
+ is(events.length, causeKeypress ? 3 : 2,
+ longDesc + "keydown" + (causeKeypress ? ", keypress" : "") + " and keyup events should be fired");
+ for (var j = 0; j < events.length; j++) {
+ is(events[j].keyCode, 0,
+ longDesc + " type=\"" + events[j].type + "\", keyCode value is not 0");
+ }
+ // If .keyCode is initialized with non-zero value, the value shouldn't be computed again.
+ var keyEventWithLocation = new KeyboardEvent("", { key: kKeyToKeyCode[i].key, keyCode: 0xFF });
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(keyEventWithLocation, baseFlags);
+ TIP.keyup(keyEventWithLocation, baseFlags);
+ longDesc = description + "testing if .keyCode is not computed for \"" + kKeyToKeyCode[i].key + "\", ";
+ is(events.length, causeKeypress ? 3 : 2,
+ longDesc + "keydown" + (causeKeypress ? ", keypress" : "") + " and keyup events should be fired");
+ for (var j = 0; j < events.length; j++) {
+ is(events[j].keyCode, events[j].type == "keypress" && kKeyToKeyCode[i].isPrintable ? 0 : 0xFF,
+ longDesc + " type=\"" + events[j].type + "\", keyCode shouldn't be computed if it's initialized with non-zero value");
+ }
+ // Unlock lockable modifier if the key is a lockable modifier key.
+ if (kKeyToKeyCode[i].isLockableModifier) {
+ TIP.keydown(keyEvent, baseFlags);
+ TIP.keyup(keyEvent, baseFlags);
+ }
+ }
+
+ // Modifier state tests
+ var sharedTIP = createTIP();
+ ok(sharedTIP.beginInputTransactionForTests(otherWindow),
+ description + "sharedTIP.beginInputTransactionForTests(otherWindow) should return true");
+ TIP.shareModifierStateOf(sharedTIP);
+ var independentTIP = createTIP();
+ const kModifierKeys = [
+ { key: "Alt", code: "AltLeft", isLockable: false },
+ { key: "Alt", code: "AltRight", isLockable: false },
+ { key: "AltGraph", code: "AltRight", isLockable: false },
+ { key: "CapsLock", code: "CapsLock", isLockable: true },
+ { key: "Control", code: "ControlLeft", isLockable: false },
+ { key: "Control", code: "ControlRight", isLockable: false },
+ { key: "Fn", code: "Fn", isLockable: false },
+ { key: "FnLock", code: "", isLockable: true },
+ { key: "Meta", code: "OSLeft", isLockable: false },
+ { key: "Meta", code: "OSRight", isLockable: false },
+ { key: "NumLock", code: "NumLock", isLockable: true },
+ { key: "ScrollLock", code: "ScrollLock", isLockable: true },
+ { key: "Shift", code: "ShiftLeft", isLockable: false },
+ { key: "Shift", code: "ShiftRight", isLockable: false },
+ { key: "Symbol", code: "", isLockable: false },
+ { key: "SymbolLock", code: "", isLockable: true },
+ { key: "OS", code: "OSLeft", isLockable: false },
+ { key: "OS", code: "OSRight", isLockable: false },
+ ];
+
+ function checkModifiers(aTestDesc, aEvent, aType, aKey, aCode, aModifiers)
+ {
+ var desc = description + aTestDesc + ", type=\"" + aEvent.type + "\", key=\"" + aEvent.key + "\", code=\"" + aEvent.code + "\"";
+ is(aEvent.type, aType,
+ desc + ", .type value is wrong");
+ if (aEvent.type != aType) {
+ return;
+ }
+ is(aEvent.key, aKey,
+ desc + ", .key value is wrong");
+ is(aEvent.code, aCode,
+ desc + ", .code value is wrong");
+ is(aEvent.altKey, aModifiers.includes("Alt"),
+ desc + ", .altKey value is wrong");
+ is(aEvent.ctrlKey, aModifiers.includes("Control"),
+ desc + ", .ctrlKey value is wrong");
+ is(aEvent.metaKey, aModifiers.includes("Meta"),
+ desc + ", .metaKey value is wrong");
+ is(aEvent.shiftKey, aModifiers.includes("Shift"),
+ desc + ", .shiftKey value is wrong");
+ /* eslint-disable-next-line no-shadow */
+ for (var i = 0; i < kModifiers.length; i++) {
+ is(aEvent.getModifierState(kModifiers[i]), aModifiers.includes(kModifiers[i]),
+ desc + ", .getModifierState(\"" + kModifiers[i] + "\") returns wrong value");
+ }
+ }
+
+ function checkAllTIPModifiers(aTestDesc, aModifiers)
+ {
+ /* eslint-disable-next-line no-shadow */
+ for (var i = 0; i < kModifiers.length; i++) {
+ is(TIP.getModifierState(kModifiers[i]), aModifiers.includes(kModifiers[i]),
+ aTestDesc + ", TIP.getModifierState(\"" + kModifiers[i] + "\") returns wrong value");
+ is(sharedTIP.getModifierState(kModifiers[i]), TIP.getModifierState(kModifiers[i]),
+ aTestDesc + ", sharedTIP.getModifierState(\"" + kModifiers[i] + "\") returns different value from TIP");
+ is(independentTIP.getModifierState(kModifiers[i]), false,
+ aTestDesc + ", independentTIP.getModifierState(\"" + kModifiers[i] + "\") should return false");
+ }
+ }
+
+ // First, all modifiers must be false.
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(keyA);
+ TIP.keyup(keyA);
+
+ is(events.length, 3,
+ description + "TIP.keydown(keyA) and TIP.keyup(keyA) should cause keydown, keypress and keyup");
+ checkModifiers("Before dispatching modifier key events", events[0], "keydown", "a", "KeyA", []);
+ checkModifiers("Before dispatching modifier key events", events[1], "keypress", "a", "KeyA", []);
+ checkModifiers("Before dispatching modifier key events", events[2], "keyup", "a", "KeyA", []);
+
+ // Test each modifier keydown/keyup causes activating/inactivating the modifier state.
+ for (var i = 0; i < kModifierKeys.length; i++) {
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ var modKey = new KeyboardEvent("", { key: kModifierKeys[i].key, code: kModifierKeys[i].code });
+ var testDesc = "A modifier key \"" + kModifierKeys[i].key + "\" (\"" + kModifierKeys[i].code + "\") and a printable key";
+ if (!kModifierKeys[i].isLockable) {
+ TIP.keydown(modKey);
+ checkAllTIPModifiers(testDesc + ", \"" + kModifierKeys[i].key + "\" keydown", [ kModifierKeys[i].key ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ kModifierKeys[i].key ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ kModifierKeys[i].key ]);
+ TIP.keyup(modKey);
+ checkAllTIPModifiers(testDesc + ", \"" + kModifierKeys[i].key + "\" keyup", [ ]);
+ is(events.length, 5,
+ description + testDesc + " should cause 5 events");
+ checkModifiers(testDesc, events[0], "keydown", kModifierKeys[i].key, kModifierKeys[i].code, [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[1], "keydown", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[2], "keypress", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[3], "keyup", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[4], "keyup", kModifierKeys[i].key, kModifierKeys[i].code, [ ]);
+
+ // KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT shouldn't cause key events of modifier keys, but should modify the modifier state.
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ testDesc = "A modifier key \"" + kModifierKeys[i].key + "\" (\"" + kModifierKeys[i].code + "\") with KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT and a printable key";
+ TIP.keydown(modKey, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ TIP.keydown(keyA);
+ TIP.keyup(keyA);
+ TIP.keyup(modKey, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ TIP.keydown(keyA);
+ TIP.keyup(keyA);
+ is(events.length, 6,
+ description + testDesc + " should cause 6 events");
+ checkModifiers(testDesc, events[0], "keydown", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[1], "keypress", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[2], "keyup", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[3], "keydown", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[4], "keypress", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[5], "keyup", "a", "KeyA", [ ]);
+ } else {
+ TIP.keydown(modKey);
+ checkAllTIPModifiers(testDesc + ", \"" + kModifierKeys[i].key + "\" first keydown", [ kModifierKeys[i].key ]);
+ TIP.keyup(modKey);
+ checkAllTIPModifiers(testDesc + ", \"" + kModifierKeys[i].key + "\" first keyup", [ kModifierKeys[i].key ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ kModifierKeys[i].key ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ kModifierKeys[i].key ]);
+ TIP.keydown(modKey);
+ checkAllTIPModifiers(testDesc + ", \"" + kModifierKeys[i].key + "\" second keydown", [ ]);
+ TIP.keyup(modKey);
+ checkAllTIPModifiers(testDesc + ", \"" + kModifierKeys[i].key + "\" second keyup", [ ]);
+ is(events.length, 7,
+ description + testDesc + " should cause 7 events");
+ checkModifiers(testDesc, events[0], "keydown", kModifierKeys[i].key, kModifierKeys[i].code, [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[1], "keyup", kModifierKeys[i].key, kModifierKeys[i].code, [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[5], "keydown", kModifierKeys[i].key, kModifierKeys[i].code, [ ]);
+ checkModifiers(testDesc, events[6], "keyup", kModifierKeys[i].key, kModifierKeys[i].code, [ ]);
+
+ // KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT shouldn't cause key events of modifier keys, but should modify the modifier state.
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ testDesc = "A modifier key \"" + kModifierKeys[i].key + "\" (\"" + kModifierKeys[i].code + "\") with KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT and a printable key";
+ TIP.keydown(modKey, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ TIP.keyup(modKey, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ TIP.keydown(keyA);
+ TIP.keyup(keyA);
+ TIP.keydown(modKey, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ TIP.keyup(modKey, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ TIP.keydown(keyA);
+ TIP.keyup(keyA);
+ is(events.length, 6,
+ description + testDesc + " should cause 6 events");
+ checkModifiers(testDesc, events[0], "keydown", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[1], "keypress", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[2], "keyup", "a", "KeyA", [ kModifierKeys[i].key ]);
+ checkModifiers(testDesc, events[3], "keydown", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[4], "keypress", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[5], "keyup", "a", "KeyA", [ ]);
+ }
+ }
+
+ // Modifier state should be inactivated only when all pressed modifiers are released
+ var shiftLeft = new KeyboardEvent("", { key: "Shift", code: "ShiftLeft" });
+ var shiftRight = new KeyboardEvent("", { key: "Shift", code: "ShiftRight" });
+ var shiftVirtual = new KeyboardEvent("", { key: "Shift", code: "" });
+ var altGrVirtual = new KeyboardEvent("", { key: "AltGraph", code: "" });
+ var ctrlVirtual = new KeyboardEvent("", { key: "Control", code: "" });
+
+ var testDesc = "ShiftLeft press -> ShiftRight press -> ShiftRight release -> ShiftLeft release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keydown", [ "Shift" ]);
+ TIP.keydown(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keydown", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift" ]);
+ TIP.keyup(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keyup", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Right-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Right-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keyup", [ ]);
+
+ is(events.length, 10,
+ description + testDesc + " should cause 10 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "ShiftLeft", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[5], "keyup", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[9], "keyup", "Shift", "ShiftLeft", [ ]);
+
+ testDesc = "ShiftLeft press -> ShiftRight press -> ShiftLeft release -> ShiftRight release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keydown", [ "Shift" ]);
+ TIP.keydown(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keydown", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift" ]);
+ TIP.keyup(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keyup", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Left-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Left-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keyup", [ ]);
+
+ is(events.length, 10,
+ description + testDesc + " should cause 10 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "ShiftLeft", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[5], "keyup", "Shift", "ShiftLeft", [ "Shift" ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[9], "keyup", "Shift", "ShiftRight", [ ]);
+
+ testDesc = "ShiftLeft press -> virtual Shift press -> virtual Shift release -> ShiftLeft release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keydown", [ "Shift" ]);
+ TIP.keydown(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keydown", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift" ]);
+ TIP.keyup(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keyup", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Virtual-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Virtual-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keyup", [ ]);
+
+ is(events.length, 10,
+ description + testDesc + " should cause 10 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "ShiftLeft", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "Shift", "", [ "Shift" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[5], "keyup", "Shift", "", [ "Shift" ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[9], "keyup", "Shift", "ShiftLeft", [ ]);
+
+ testDesc = "virtual Shift press -> ShiftRight press -> ShiftRight release -> virtual Shift release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keydown", [ "Shift" ]);
+ TIP.keydown(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keydown", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift" ]);
+ TIP.keyup(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keyup", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Right-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Right-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keyup", [ ]);
+
+ is(events.length, 10,
+ description + testDesc + " should cause 10 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[5], "keyup", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[9], "keyup", "Shift", "", [ ]);
+
+ testDesc = "ShiftLeft press -> ShiftRight press -> ShiftRight release -> ShiftRight release -> ShiftLeft release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keydown", [ "Shift" ]);
+ TIP.keydown(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keydown", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift" ]);
+ TIP.keyup(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keyup", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Virtual-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Virtual-Shift keyup)", [ "Shift" ]);
+ TIP.keyup(shiftRight);
+ checkAllTIPModifiers(testDesc + ", Right-Shift keyup again", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Virtual-Shift keyup again)", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Virtual-Shift keyup again)", [ "Shift" ]);
+ TIP.keyup(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keyup", [ ]);
+
+ is(events.length, 14,
+ description + testDesc + " should cause 14 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "ShiftLeft", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[5], "keyup", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[9], "keyup", "Shift", "ShiftRight", [ "Shift" ]);
+ checkModifiers(testDesc, events[10], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[11], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[12], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[13], "keyup", "Shift", "ShiftLeft", [ ]);
+
+ testDesc = "ShiftLeft press -> ShiftLeft press -> ShiftLeft release -> ShiftLeft release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keydown", [ "Shift" ]);
+ TIP.keydown(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keydown again", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift" ]);
+ TIP.keyup(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keyup", [ ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Left-Shift keyup)", [ ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Left-Shift keyup)", [ ]);
+ TIP.keyup(shiftLeft);
+ checkAllTIPModifiers(testDesc + ", Left-Shift keyup again", [ ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Left-Shift keyup again)", [ ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Left-Shift keyup again)", [ ]);
+
+ is(events.length, 13,
+ description + testDesc + " should cause 13 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "ShiftLeft", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "Shift", "ShiftLeft", [ "Shift" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[5], "keyup", "Shift", "ShiftLeft", [ ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[9], "keyup", "Shift", "ShiftLeft", [ ]);
+ checkModifiers(testDesc, events[10], "keydown", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[11], "keypress", "a", "KeyA", [ ]);
+ checkModifiers(testDesc, events[12], "keyup", "a", "KeyA", [ ]);
+
+ testDesc = "virtual Shift press -> virtual AltGraph press -> virtual AltGraph release -> virtual Shift release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keydown", [ "Shift" ]);
+ TIP.keydown(altGrVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-AltGraph keydown", [ "Shift", "AltGraph" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift", "AltGraph" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift", "AltGraph" ]);
+ TIP.keyup(altGrVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-AltGraph keyup", [ "Shift" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Virtual-AltGraph keyup)", [ "Shift" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Virtual-AltGraph keyup)", [ "Shift" ]);
+ TIP.keyup(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keyup", [ ]);
+
+ is(events.length, 10,
+ description + testDesc + " should cause 10 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "AltGraph", "", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[5], "keyup", "AltGraph", "", [ "Shift" ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ "Shift" ]);
+ checkModifiers(testDesc, events[9], "keyup", "Shift", "", [ ]);
+
+ testDesc = "virtual Shift press -> virtual AltGraph press -> virtual Shift release -> virtual AltGr release";
+ reset();
+ doPreventDefaults = [ "keypress" ];
+ TIP.keydown(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keydown", [ "Shift" ]);
+ TIP.keydown(altGrVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-AltGraph keydown", [ "Shift", "AltGraph" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown", [ "Shift", "AltGraph" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup", [ "Shift", "AltGraph" ]);
+ TIP.keyup(shiftVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-Shift keyup", [ "AltGraph" ]);
+ TIP.keydown(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keydown (after Virtual-Shift keyup)", [ "AltGraph" ]);
+ TIP.keyup(keyA);
+ checkAllTIPModifiers(testDesc + ", \"a\" keyup (after Virtual-Shift keyup)", [ "AltGraph" ]);
+ TIP.keyup(altGrVirtual);
+ checkAllTIPModifiers(testDesc + ", Virtual-AltGraph keyup", [ ]);
+
+ is(events.length, 10,
+ description + testDesc + " should cause 10 events");
+ checkModifiers(testDesc, events[0], "keydown", "Shift", "", [ "Shift" ]);
+ checkModifiers(testDesc, events[1], "keydown", "AltGraph", "", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[2], "keydown", "a", "KeyA", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[3], "keypress", "a", "KeyA", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[4], "keyup", "a", "KeyA", [ "Shift", "AltGraph" ]);
+ checkModifiers(testDesc, events[5], "keyup", "Shift", "", [ "AltGraph" ]);
+ checkModifiers(testDesc, events[6], "keydown", "a", "KeyA", [ "AltGraph" ]);
+ checkModifiers(testDesc, events[7], "keypress", "a", "KeyA", [ "AltGraph" ]);
+ checkModifiers(testDesc, events[8], "keyup", "a", "KeyA", [ "AltGraph" ]);
+ checkModifiers(testDesc, events[9], "keyup", "AltGraph", "", [ ]);
+
+ // shareModifierStateOf(null) should cause resetting the modifier state
+ function checkTIPModifiers(aTestDesc, aTIP, aModifiers)
+ {
+ /* eslint-disable-next-line no-shadow */
+ for (var i = 0; i < kModifiers.length; i++) {
+ is(aTIP.getModifierState(kModifiers[i]), aModifiers.includes(kModifiers[i]),
+ description + aTestDesc + ", aTIP.getModifierState(\"" + kModifiers[i] + "\") returns wrong value");
+ }
+ }
+ TIP.keydown(shiftVirtual);
+ TIP.keydown(altGrVirtual);
+ sharedTIP.shareModifierStateOf(null);
+ checkTIPModifiers("sharedTIP.sharedModifierStateOf(null) shouldn't cause TIP's modifiers reset", TIP, [ "Shift", "AltGraph" ]);
+ checkTIPModifiers("sharedTIP.sharedModifierStateOf(null) should cause sharedTIP modifiers reset", sharedTIP, [ ]);
+
+ // sharedTIP.shareModifierStateOf(null) should be unlinked from TIP.
+ TIP.keydown(ctrlVirtual);
+ checkTIPModifiers("TIP.keydown(ctrlVirtual) should cause TIP's modifiers set", TIP, [ "Shift", "AltGraph", "Control" ]);
+ checkTIPModifiers("TIP.keydown(ctrlVirtual) shouldn't cause sharedTIP modifiers set", sharedTIP, [ ]);
+
+ // beginInputTransactionForTests() shouldn't cause modifier state reset.
+ ok(TIP.beginInputTransactionForTests(otherWindow),
+ description + "TIP.beginInputTransactionForTests(otherWindow) should return true");
+ checkTIPModifiers("TIP.beginInputTransactionForTests(otherWindow) shouldn't cause TIP's modifiers set", TIP, [ "Shift", "AltGraph", "Control" ]);
+ TIP.keyup(shiftLeft);
+ TIP.keyup(altGrVirtual);
+ TIP.keyup(ctrlVirtual);
+ checkTIPModifiers("TIP should keep modifier's physical key state", TIP, [ "Shift" ]);
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests(window) should return true");
+ checkTIPModifiers("TIP.beginInputTransactionForTests(window) shouldn't cause TIP's modifiers set", TIP, [ "Shift" ]);
+ TIP.keyup(shiftVirtual);
+ checkTIPModifiers("TIP should keep modifier's physical key state", TIP, [ ]);
+
+ window.removeEventListener("keydown", handler, false);
+ window.removeEventListener("keypress", handler, false);
+ window.removeEventListener("keyup", handler, false);
+}
+
+function runErrorTests()
+{
+ var description = "runErrorTests(): ";
+
+ var TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ input.value = "";
+ input.focus();
+
+ // startComposition() should throw an exception if there is already a composition
+ TIP.startComposition();
+ try {
+ TIP.startComposition();
+ ok(false,
+ description + "startComposition() should fail if it was already called");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_FAILURE"),
+ description + "startComposition() should cause NS_ERROR_FAILURE if there is already composition");
+ } finally {
+ TIP.cancelComposition();
+ }
+
+ // cancelComposition() should throw an exception if there is no composition
+ try {
+ TIP.cancelComposition();
+ ok(false,
+ description + "cancelComposition() should fail if there is no composition");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_FAILURE"),
+ description + "cancelComposition() should cause NS_ERROR_FAILURE if there is no composition");
+ }
+
+ // commitComposition() without commit string should throw an exception if there is no composition
+ try {
+ TIP.commitComposition();
+ ok(false,
+ description + "commitComposition() should fail if there is no composition");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_FAILURE"),
+ description + "commitComposition() should cause NS_ERROR_FAILURE if there is no composition");
+ }
+
+ // commitCompositionWith("") should throw an exception if there is no composition
+ try {
+ TIP.commitCompositionWith("");
+ ok(false,
+ description + "commitCompositionWith(\"\") should fail if there is no composition");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_FAILURE"),
+ description + "commitCompositionWith(\"\") should cause NS_ERROR_FAILURE if there is no composition");
+ }
+
+ // Pending composition string should allow to flush without clause information (for compatibility)
+ try {
+ TIP.setPendingCompositionString("foo");
+ TIP.flushPendingComposition();
+ ok(true,
+ description + "flushPendingComposition() should succeed even if appendClauseToPendingComposition() has never been called");
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(false,
+ description + "flushPendingComposition() shouldn't cause an exception even if appendClauseToPendingComposition() has never been called");
+ }
+
+ // Pending composition string must be filled by clause information
+ try {
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(2, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ ok(false,
+ description + "flushPendingComposition() should fail if appendClauseToPendingComposition() doesn't fill all composition string");
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "flushPendingComposition() should cause NS_ERROR_ILLEGAL_VALUE if appendClauseToPendingComposition() doesn't fill all composition string");
+ }
+
+ // Pending composition string must not be shorter than appended clause length
+ try {
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(4, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ ok(false,
+ description + "flushPendingComposition() should fail if appendClauseToPendingComposition() appends longer clause information");
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "flushPendingComposition() should cause NS_ERROR_ILLEGAL_VALUE if appendClauseToPendingComposition() appends longer clause information");
+ }
+
+ // Pending composition must not have clause information with empty string
+ try {
+ TIP.appendClauseToPendingComposition(1, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ ok(false,
+ description + "flushPendingComposition() should fail if there is a clause with empty string");
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "flushPendingComposition() should cause NS_ERROR_ILLEGAL_VALUE if there is a clause with empty string");
+ }
+
+ // Appending a clause whose length is 0 should cause an exception
+ try {
+ TIP.appendClauseToPendingComposition(0, TIP.ATTR_RAW_CLAUSE);
+ ok(false,
+ description + "appendClauseToPendingComposition() should fail if the length is 0");
+ TIP.flushPendingComposition();
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "appendClauseToPendingComposition() should cause NS_ERROR_ILLEGAL_VALUE if the length is 0");
+ }
+
+ // Appending a clause whose attribute is invalid should cause an exception
+ try {
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, 0);
+ ok(false,
+ description + "appendClauseToPendingComposition() should fail if the attribute is invalid");
+ TIP.flushPendingComposition();
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "appendClauseToPendingComposition() should cause NS_ERROR_ILLEGAL_VALUE if the attribute is invalid");
+ }
+
+ // Setting caret position outside of composition string should cause an exception
+ try {
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(4);
+ TIP.flushPendingComposition();
+ ok(false,
+ description + "flushPendingComposition() should fail if caret position is out of composition string");
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "flushPendingComposition() should cause NS_ERROR_ILLEGAL_VALUE if caret position is out of composition string");
+ }
+
+ // Calling keydown() with a KeyboardEvent initialized with invalid code value should cause an exception.
+ input.value = "";
+ try {
+ var keyInvalidCode = new KeyboardEvent("", { key: "f", code: "InvalidCodeValue", keyCode: KeyboardEvent.DOM_VK_F });
+ TIP.keydown(keyInvalidCode);
+ ok(false,
+ description + "TIP.keydown(keyInvalidCode) should cause throwing an exception because its code value is not registered");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "TIP.keydown(keyInvalidCode) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not be modified");
+ }
+
+ // Calling keyup() with a KeyboardEvent initialized with invalid code value should cause an exception.
+ input.value = "";
+ try {
+ var keyInvalidCode = new KeyboardEvent("", { key: "f", code: "InvalidCodeValue", keyCode: KeyboardEvent.DOM_VK_F });
+ TIP.keyup(keyInvalidCode);
+ ok(false,
+ description + "TIP.keyup(keyInvalidCode) should cause throwing an exception because its code value is not registered");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "TIP.keyup(keyInvalidCode) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not be modified");
+ }
+
+ // Calling keydown(KEY_NON_PRINTABLE_KEY) with a KeyboardEvent initialized with non-key name should cause an exception.
+ input.value = "";
+ try {
+ var keyInvalidKey = new KeyboardEvent("", { key: "ESCAPE", code: "Escape", keyCode: KeyboardEvent.DOM_VK_Escape});
+ TIP.keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY);
+ ok(false,
+ description + "TIP.keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception because its key value is not registered");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not be modified");
+ }
+
+ // Calling keyup(KEY_NON_PRINTABLE_KEY) with a KeyboardEvent initialized with non-key name should cause an exception.
+ input.value = "";
+ try {
+ var keyInvalidKey = new KeyboardEvent("", { key: "ESCAPE", code: "Escape", keyCode: KeyboardEvent.DOM_VK_Escape});
+ TIP.keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY);
+ ok(false,
+ description + "TIP.keyup(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception because its key value is not registered");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keyup(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
+ } finally {
+ is(input.value, "",
+ description + "The input element should not be modified");
+ }
+
+ // KEY_KEEP_KEY_LOCATION_STANDARD flag should be used only when .location is not initialized with non-zero value.
+ try {
+ var keyEvent = new KeyboardEvent("", { code: "Enter", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT });
+ TIP.keydown(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+ ok(false,
+ description + "keydown(KEY_KEEP_KEY_LOCATION_STANDARD) should fail if the .location of the key event is initialized with non-zero value");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keydown(KEY_KEEP_KEY_LOCATION_STANDARD) should cause NS_ERROR_ILLEGAL_VALUE if the .location of the key event is initialized with nonzero value");
+ }
+ try {
+ var keyEvent = new KeyboardEvent("", { code: "Enter", location: KeyboardEvent.DOM_KEY_LOCATION_LEFT });
+ TIP.keyup(keyEvent, TIP.KEY_KEEP_KEY_LOCATION_STANDARD);
+ ok(false,
+ description + "keyup(KEY_KEEP_KEY_LOCATION_STANDARD) should fail if the .location of the key event is initialized with non-zero value");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keyup(KEY_KEEP_KEY_LOCATION_STANDARD) should cause NS_ERROR_ILLEGAL_VALUE if the .location of the key event is initialized with nonzero value");
+ }
+
+ // KEY_KEEP_KEYCODE_ZERO flag should be used only when .keyCode is not initialized with non-zero value.
+ try {
+ var keyEvent = new KeyboardEvent("", { key: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ TIP.keydown(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO);
+ ok(false,
+ description + "keydown(KEY_KEEP_KEYCODE_ZERO) should fail if the .keyCode of the key event is initialized with non-zero value");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keydown(KEY_KEEP_KEYCODE_ZERO) should cause NS_ERROR_ILLEGAL_VALUE if the .keyCode of the key event is initialized with nonzero value");
+ }
+ try {
+ var keyEvent = new KeyboardEvent("", { key: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
+ TIP.keyup(keyEvent, TIP.KEY_KEEP_KEYCODE_ZERO);
+ ok(false,
+ description + "keyup(KEY_KEEP_KEYCODE_ZERO) should fail if the .keyCode of the key event is initialized with non-zero value");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keyup(KEY_KEEP_KEYCODE_ZERO) should cause NS_ERROR_ILLEGAL_VALUE if the .keyCode of the key event is initialized with nonzero value");
+ }
+
+ // Specifying KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT with non-modifier key, it should cause an exception.
+ try {
+ var keyEvent = new KeyboardEvent("", { key: "a", code: "ShiftLeft" });
+ TIP.keyup(keyEvent, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ ok(false,
+ description + "keydown(KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT) should fail if the .key value isn't a modifier key");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keydown(KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT) should cause NS_ERROR_ILLEGAL_VALUE if the .key value isn't a modifier key");
+ }
+ try {
+ var keyEvent = new KeyboardEvent("", { key: "Enter", code: "ShiftLeft" });
+ TIP.keyup(keyEvent, TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
+ ok(false,
+ description + "keydown(KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT) should fail if the .key value isn't a modifier key");
+ } catch (e) {
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ description + "keydown(KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT) should cause NS_ERROR_ILLEGAL_VALUE if the .key value isn't a modifier key");
+ }
+
+ // The type of key events specified to composition methods should be "" or "keydown".
+ var kKeyEventTypes = [
+ { type: "keydown", valid: true },
+ { type: "keypress", valid: false },
+ { type: "keyup", valid: false },
+ { type: "", valid: true },
+ { type: "mousedown", valid: false },
+ { type: "foo", valid: false },
+ ];
+ for (var i = 0; i < kKeyEventTypes[i].length; i++) {
+ var keyEvent =
+ new KeyboardEvent(kKeyEventTypes[i].type, { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
+ var testDescription = description + "type=\"" + kKeyEventTypes[i].type + "\", ";
+ try {
+ TIP.startComposition(keyEvent);
+ ok(kKeyEventTypes[i].valid,
+ testDescription + "TIP.startComposition(keyEvent) should not accept the event type");
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(!kKeyEventTypes[i].valid,
+ testDescription + "TIP.startComposition(keyEvent) should not throw an exception for the event type");
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ testDescription + "TIP.startComposition(keyEvent) should cause NS_ERROR_ILLEGAL_VALUE if the key event type isn't valid");
+ }
+ try {
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition(keyEvent);
+ ok(kKeyEventTypes[i].valid,
+ testDescription + "TIP.flushPendingComposition(keyEvent) should not accept the event type");
+ TIP.cancelComposition();
+ } catch (e) {
+ ok(!kKeyEventTypes[i].valid,
+ testDescription + "TIP.flushPendingComposition(keyEvent) should not throw an exception for the event type");
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ testDescription + "TIP.flushPendingComposition(keyEvent) should cause NS_ERROR_ILLEGAL_VALUE if the key event type isn't valid");
+ }
+ try {
+ TIP.startComposition();
+ TIP.commitComposition(keyEvent);
+ ok(kKeyEventTypes[i].valid,
+ testDescription + "TIP.commitComposition(keyEvent) should not accept the event type");
+ } catch (e) {
+ ok(!kKeyEventTypes[i].valid,
+ testDescription + "TIP.commitComposition(keyEvent) should not throw an exception for the event type");
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ testDescription + "TIP.commitComposition(keyEvent) should cause NS_ERROR_ILLEGAL_VALUE if the key event type isn't valid");
+ TIP.cancelComposition();
+ }
+ try {
+ TIP.commitCompositionWith("foo", keyEvent);
+ ok(kKeyEventTypes[i].valid,
+ testDescription + "TIP.commitCompositionWith(\"foo\", keyEvent) should not accept the event type");
+ } catch (e) {
+ ok(!kKeyEventTypes[i].valid,
+ testDescription + "TIP.commitCompositionWith(\"foo\", keyEvent) should not throw an exception for the event type");
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ testDescription + "TIP.commitCompositionWith(\"foo\", keyEvent) should cause NS_ERROR_ILLEGAL_VALUE if the key event type isn't valid");
+ }
+ try {
+ TIP.startComposition();
+ TIP.cancelComposition(keyEvent);
+ ok(kKeyEventTypes[i].valid,
+ testDescription + "TIP.cancelComposition(keyEvent) should not accept the event type");
+ } catch (e) {
+ ok(!kKeyEventTypes[i].valid,
+ testDescription + "TIP.cancelComposition(keyEvent) should not throw an exception for the event type");
+ ok(e.message.includes("NS_ERROR_ILLEGAL_VALUE"),
+ testDescription + "TIP.cancelComposition(keyEvent) should cause NS_ERROR_ILLEGAL_VALUE if the key event type isn't valid");
+ TIP.cancelComposition();
+ }
+ input.value = "";
+ }
+}
+
+function runCommitCompositionTests()
+{
+ var description = "runCommitCompositionTests(): ";
+
+ var TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(window),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ input.focus();
+
+ // commitComposition() should commit the composition with the last data.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ TIP.commitComposition();
+ is(input.value, "foo",
+ description + "commitComposition() should commit the composition with the last data");
+
+ // commitCompositionWith("") should commit the composition with empty string.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ TIP.commitCompositionWith("");
+ is(input.value, "",
+ description + "commitCompositionWith(\"\") should commit the composition with empty string");
+
+ function doCommit(aText)
+ {
+ TIP.commitCompositionWith(aText);
+ }
+
+ // doCommit() should commit the composition with the last data.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommit();
+ todo_is(input.value, "foo",
+ description + "doCommit() should commit the composition with the last data");
+
+ // doCommit("") should commit the composition with empty string.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommit("");
+ is(input.value, "",
+ description + "doCommit(\"\") should commit the composition with empty string");
+
+ // doCommit(null) should commit the composition with empty string.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommit(null);
+ is(input.value, "",
+ description + "doCommit(null) should commit the composition with empty string");
+
+ // doCommit(undefined) should commit the composition with the last data.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommit(undefined);
+ todo_is(input.value, "foo",
+ description + "doCommit(undefined) should commit the composition with the last data");
+
+ function doCommitWithNullCheck(aText)
+ {
+ TIP.commitCompositionWith(aText ? aText : "");
+ }
+
+ // doCommitWithNullCheck() should commit the composition with the last data.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommitWithNullCheck();
+ is(input.value, "",
+ description + "doCommitWithNullCheck() should commit the composition with empty string");
+
+ // doCommitWithNullCheck("") should commit the composition with empty string.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommitWithNullCheck("");
+ is(input.value, "",
+ description + "doCommitWithNullCheck(\"\") should commit the composition with empty string");
+
+ // doCommitWithNullCheck(null) should commit the composition with empty string.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommitWithNullCheck(null);
+ is(input.value, "",
+ description + "doCommitWithNullCheck(null) should commit the composition with empty string");
+
+ // doCommitWithNullCheck(undefined) should commit the composition with the last data.
+ input.value = "";
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ doCommitWithNullCheck(undefined);
+ is(input.value, "",
+ description + "doCommitWithNullCheck(undefined) should commit the composition with empty string");
+}
+
+function runUnloadTests1()
+{
+ return new Promise(resolve => {
+ let description = "runUnloadTests1(): ";
+
+ let TIP1 = createTIP();
+ ok(TIP1.beginInputTransactionForTests(childWindow),
+ description + "TIP1.beginInputTransactionForTests() should succeed");
+
+ let oldSrc = iframe.src;
+ let parentWindow = window;
+
+ iframe.addEventListener("load", function (aEvent) {
+ ok(true, description + "dummy page is loaded");
+ childWindow = iframe.contentWindow;
+ textareaInFrame = null;
+ iframe.addEventListener("load", function () {
+ ok(true, description + "old iframe is restored");
+ // And also restore the iframe information with restored contents.
+ childWindow = iframe.contentWindow;
+ textareaInFrame = iframe.contentDocument.getElementById("textarea");
+ SimpleTest.executeSoon(resolve);
+ }, {capture: true, once: true});
+
+ // The composition should be committed internally. So, another TIP should
+ // be able to steal the rights to using TextEventDispatcher.
+ let TIP2 = createTIP();
+ ok(TIP2.beginInputTransactionForTests(parentWindow),
+ description + "TIP2.beginInputTransactionForTests() should succeed");
+
+ input.focus();
+ input.value = "";
+
+ TIP2.setPendingCompositionString("foo");
+ TIP2.appendClauseToPendingComposition(3, TIP2.ATTR_RAW_CLAUSE);
+ TIP2.setCaretInPendingComposition(3);
+ TIP2.flushPendingComposition();
+ is(input.value, "foo",
+ description + "the input in the parent document should have composition string");
+
+ TIP2.cancelComposition();
+
+ // Restore the old iframe content.
+ iframe.src = oldSrc;
+ }, {capture: true, once: true});
+
+ // Start composition in the iframe.
+ textareaInFrame.value = "";
+ textareaInFrame.focus();
+
+ TIP1.setPendingCompositionString("foo");
+ TIP1.appendClauseToPendingComposition(3, TIP1.ATTR_RAW_CLAUSE);
+ TIP1.setCaretInPendingComposition(3);
+ TIP1.flushPendingComposition();
+ is(textareaInFrame.value, "foo",
+ description + "the textarea in the iframe should have composition string");
+
+ // Load different web page on the frame.
+ iframe.src = "data:text/html,<body>dummy page</body>";
+ });
+}
+
+function runUnloadTests2()
+{
+ return new Promise(resolve => {
+ let description = "runUnloadTests2(): ";
+
+ let TIP = createTIP();
+ ok(TIP.beginInputTransactionForTests(childWindow),
+ description + "TIP.beginInputTransactionForTests() should succeed");
+
+ let oldSrc = iframe.src;
+
+ iframe.addEventListener("load", function (aEvent) {
+ ok(true, description + "dummy page is loaded");
+ childWindow = iframe.contentWindow;
+ textareaInFrame = null;
+ iframe.addEventListener("load", function () {
+ ok(true, description + "old iframe is restored");
+ // And also restore the iframe information with restored contents.
+ childWindow = iframe.contentWindow;
+ textareaInFrame = iframe.contentDocument.getElementById("textarea");
+ SimpleTest.executeSoon(resolve);
+ }, {capture: true, once: true});
+
+ input.focus();
+ input.value = "";
+
+ // TIP should be still available in the same top level widget.
+ TIP.setPendingCompositionString("bar");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ if (input.value == "") {
+ // XXX TextInputProcessor or TextEventDispatcher may have a bug.
+ todo_is(input.value, "bar",
+ description + "the input in the parent document should have composition string");
+ } else {
+ is(input.value, "bar",
+ description + "the input in the parent document should have composition string");
+ }
+
+ TIP.cancelComposition();
+
+ // Restore the old iframe content.
+ iframe.src = oldSrc;
+ }, {capture: true, once: true});
+
+ // Start composition in the iframe.
+ textareaInFrame.value = "";
+ textareaInFrame.focus();
+
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.setCaretInPendingComposition(3);
+ TIP.flushPendingComposition();
+ is(textareaInFrame.value, "foo",
+ description + "the textarea in the iframe should have composition string");
+
+ // Load different web page on the frame.
+ iframe.src = "data:text/html,<body>dummy page</body>";
+ });
+}
+
+async function runCallbackTests(aForTests)
+{
+ let description = "runCallbackTests(aForTests=" + aForTests + "): ";
+
+ input.value = "";
+ input.focus();
+ input.blur();
+
+ let TIP = createTIP();
+ let notifications = [];
+ let waitingNextNotification;
+ function callback(aTIP, aNotification)
+ {
+ if (aTIP == TIP) {
+ notifications.push(aNotification);
+ }
+ switch (aNotification.type) {
+ case "request-to-commit":
+ aTIP.commitComposition();
+ break;
+ case "request-to-cancel":
+ aTIP.cancelComposition();
+ break;
+ }
+ if (waitingNextNotification) {
+ SimpleTest.executeSoon(waitingNextNotification);
+ waitingNextNotification = undefined;
+ }
+ return true;
+ }
+
+ function dumpUnexpectedNotifications(aExpectedCount)
+ {
+ if (notifications.length <= aExpectedCount) {
+ return;
+ }
+ for (let i = aExpectedCount; i < notifications.length; i++) {
+ ok(false,
+ description + "Unexpected notification: " + notifications[i].type);
+ }
+ }
+
+ function waitUntilNotificationsReceived()
+ {
+ return new Promise(resolve => {
+ if (notifications.length) {
+ SimpleTest.executeSoon(resolve);
+ } else {
+ waitingNextNotification = resolve;
+ }
+ });
+ }
+
+ function checkPositionChangeNotification(aNotification, aDescription)
+ {
+ is(!aNotification || aNotification.type, "notify-position-change",
+ aDescription + " should cause position change notification");
+ }
+
+ function checkSelectionChangeNotification(aNotification, aDescription, aExpected)
+ {
+ is(aNotification.type, "notify-selection-change",
+ aDescription + " should cause selection change notification");
+ if (aNotification.type != "notify-selection-change") {
+ return;
+ }
+ is(aNotification.hasRange, aExpected.hasRange !== false,
+ `${aDescription} should cause selection change notification whose hasRange is ${aExpected.hasRange}`);
+ if (aNotification.hasRange) {
+ is(aNotification.offset, aExpected.offset,
+ `${aDescription} should cause selection change notification whose offset is ${aExpected.offset}`);
+ is(aNotification.text, aExpected.text,
+ `${aDescription} should cause selection change notification whose text is "${aExpected.text}"`);
+ is(aNotification.length, aExpected.text.length,
+ `${aDescription} should cause selection change notification whose length is ${aExpected.text.length}`);
+ is(aNotification.reversed, aExpected.reversed || false,
+ `${aDescription} should cause selection change notification whose reversed is ${aExpected.reversed || false}`);
+ }
+ is(aNotification.collapsed, aExpected.hasRange === false || !aExpected.text.length,
+ `${aDescription} should cause selection change notification whose collapsed is ${aExpected.hasRange === false || !aExpected.text.length}`);
+ is(aNotification.writingMode, aExpected.writingMode || "horizontal-tb",
+ `${aDescription} should cause selection change notification whose writingMode is ${aExpected.writingMode || "horizontal-tb"}`);
+ is(aNotification.causedByComposition, aExpected.causedByComposition || false,
+ `${aDescription} should cause selection change notification whose causedByComposition is ${aExpected.causedByComposition || false}`);
+ is(aNotification.causedBySelectionEvent, aExpected.causedBySelectionEvent || false,
+ `${aDescription} should cause selection change notification whose causedBySelectionEvent is ${aExpected.causedBySelectionEvent || false}`);
+ is(aNotification.occurredDuringComposition, aExpected.occurredDuringComposition || false,
+ `${aDescription} should cause cause selection change notification whose occurredDuringComposition is ${aExpected.occurredDuringComposition || false}`);
+ }
+
+ function checkTextChangeNotification(aNotification, aDescription, aExpected)
+ {
+ is(aNotification.type, "notify-text-change",
+ aDescription + " should cause text change notification");
+ if (aNotification.type != "notify-text-change") {
+ return;
+ }
+ is(aNotification.offset, aExpected.offset,
+ aDescription + " should cause text change notification whose offset is " + aExpected.offset);
+ is(aNotification.removedLength, aExpected.removedLength,
+ aDescription + " should cause text change notification whose removedLength is " + aExpected.removedLength);
+ is(aNotification.addedLength, aExpected.addedLength,
+ aDescription + " should cause text change notification whose addedLength is " + aExpected.addedLength);
+ is(aNotification.causedOnlyByComposition, aExpected.causedOnlyByComposition || false,
+ aDescription + " should cause text change notification whose causedOnlyByComposition is " + (aExpected.causedOnlyByComposition || false));
+ is(aNotification.includingChangesDuringComposition, aExpected.includingChangesDuringComposition || false,
+ aDescription + " should cause text change notification whose includingChangesDuringComposition is " + (aExpected.includingChangesDuringComposition || false));
+ is(aNotification.includingChangesWithoutComposition, typeof aExpected.includingChangesWithoutComposition === "boolean" ? aExpected.includingChangesWithoutComposition : true,
+ aDescription + " should cause text change notification whose includingChangesWithoutComposition is " + (typeof aExpected.includingChangesWithoutComposition === "boolean" ? aExpected.includingChangesWithoutComposition : true));
+ }
+
+ if (aForTests) {
+ TIP.beginInputTransactionForTests(window, callback);
+ } else {
+ TIP.beginInputTransaction(window, callback);
+ }
+
+ notifications = [];
+ input.focus();
+ is(notifications.length, 1,
+ description + "input.focus() should cause a notification");
+ is(notifications[0].type, "notify-focus",
+ description + "input.focus() should cause \"notify-focus\"");
+ dumpUnexpectedNotifications(1);
+
+ notifications = [];
+ input.blur();
+ is(notifications.length, 1,
+ description + "input.blur() should cause a notification");
+ is(notifications[0].type, "notify-blur",
+ description + "input.blur() should cause \"notify-focus\"");
+ dumpUnexpectedNotifications(1);
+
+ input.focus();
+ await waitUntilNotificationsReceived();
+ notifications = [];
+ TIP.setPendingCompositionString("foo");
+ TIP.appendClauseToPendingComposition(3, TIP.ATTR_RAW_CLAUSE);
+ TIP.flushPendingComposition();
+ is(notifications.length, 3,
+ description + "creating composition string 'foo' should cause 3 notifications");
+ checkTextChangeNotification(notifications[0], description + "creating composition string 'foo'",
+ { offset: 0, removedLength: 0, addedLength: 3,
+ causedOnlyByComposition: true, includingChangesDuringComposition: false, includingChangesWithoutComposition: false});
+ checkSelectionChangeNotification(notifications[1], description + "creating composition string 'foo'",
+ { offset: 3, text: "", causedByComposition: true, occurredDuringComposition: true });
+ checkPositionChangeNotification(notifications[2], description + "creating composition string 'foo'");
+ dumpUnexpectedNotifications(3);
+
+ notifications = [];
+ synthesizeMouseAtCenter(input, {});
+ is(notifications.length, 3,
+ description + "synthesizeMouseAtCenter(input, {}) during composition should cause 3 notifications");
+ is(notifications[0].type, "request-to-commit",
+ description + "synthesizeMouseAtCenter(input, {}) during composition should cause \"request-to-commit\"");
+ checkTextChangeNotification(notifications[1], description + "synthesizeMouseAtCenter(input, {}) during composition",
+ { offset: 0, removedLength: 3, addedLength: 3,
+ causedOnlyByComposition: true, includingChangesDuringComposition: false, includingChangesWithoutComposition: false});
+ checkPositionChangeNotification(notifications[2], description + "synthesizeMouseAtCenter(input, {}) during composition");
+ dumpUnexpectedNotifications(3);
+
+ input.focus();
+ await waitUntilNotificationsReceived();
+ notifications = [];
+ // XXX On macOS, window.moveBy() doesn't cause notify-position-change.
+ // Investigate this later (although, we cannot notify position change to
+ // native IME on macOS).
+ // Wayland also does not support it.
+ var isWayland = Services.prefs.getBoolPref("widget.wayland.test-workarounds.enabled", false);
+ if (!kIsMac && !isWayland) {
+ window.moveBy(0, 10);
+ await waitUntilNotificationsReceived();
+ is(notifications.length, 1,
+ description + "window.moveBy(0, 10) should cause a notification");
+ checkPositionChangeNotification(notifications[0], description + "window.moveBy(0, 10)");
+ dumpUnexpectedNotifications(1);
+
+ notifications = [];
+ window.moveBy(10, 0);
+ await waitUntilNotificationsReceived();
+ is(notifications.length, 1,
+ description + "window.moveBy(10, 0) should cause a notification");
+ checkPositionChangeNotification(notifications[0], description + "window.moveBy(10, 0)");
+ dumpUnexpectedNotifications(1);
+ }
+
+ input.focus();
+ input.value = "abc"
+ notifications = [];
+ input.selectionStart = input.selectionEnd = 0;
+ await waitUntilNotificationsReceived();
+ notifications = [];
+ let rightArrowKeyEvent =
+ new KeyboardEvent("", { key: "ArrowRight", code: "ArrowRight", keyCode: KeyboardEvent.DOM_VK_RIGHT });
+ TIP.keydown(rightArrowKeyEvent);
+ TIP.keyup(rightArrowKeyEvent);
+ is(notifications.length, 1,
+ description + "ArrowRight key press should cause a notification");
+ checkSelectionChangeNotification(notifications[0], description + "ArrowRight key press", { offset: 1, text: "" });
+ dumpUnexpectedNotifications(1);
+
+ notifications = [];
+ let shiftKeyEvent =
+ new KeyboardEvent("", { key: "Shift", code: "ShiftLeft", keyCode: KeyboardEvent.DOM_VK_SHIFT });
+ let leftArrowKeyEvent =
+ new KeyboardEvent("", { key: "ArrowLeft", code: "ArrowLeft", keyCode: KeyboardEvent.DOM_VK_LEFT });
+ TIP.keydown(shiftKeyEvent);
+ TIP.keydown(leftArrowKeyEvent);
+ TIP.keyup(leftArrowKeyEvent);
+ TIP.keyup(shiftKeyEvent);
+ is(notifications.length, 1,
+ description + "ArrowLeft key press with Shift should cause a notification");
+ checkSelectionChangeNotification(notifications[0], description + "ArrowLeft key press with Shift", { offset: 0, text: "a", reversed: true });
+ dumpUnexpectedNotifications(1);
+
+ TIP.keydown(rightArrowKeyEvent);
+ TIP.keyup(rightArrowKeyEvent);
+ notifications = [];
+ TIP.keydown(shiftKeyEvent);
+ TIP.keydown(rightArrowKeyEvent);
+ TIP.keyup(rightArrowKeyEvent);
+ TIP.keyup(shiftKeyEvent);
+ is(notifications.length, 1,
+ description + "ArrowRight key press with Shift should cause a notification");
+ checkSelectionChangeNotification(notifications[0], description + "ArrowRight key press with Shift", { offset: 1, text: "b" });
+ dumpUnexpectedNotifications(1);
+
+ notifications = [];
+ input.editor.selection.removeAllRanges();
+ await waitUntilNotificationsReceived();
+ is(notifications.length, 1,
+ `${description}Removing all selection ranges should cause a selection change notification`);
+ checkSelectionChangeNotification(
+ notifications[0],
+ `${description}Removing all selection ranges in editor`,
+ { hasRange: false }
+ );
+ dumpUnexpectedNotifications(1);
+
+ notifications = [];
+ let TIP2 = createTIP();
+ if (aForTests) {
+ TIP2.beginInputTransactionForTests(window, callback);
+ } else {
+ TIP2.beginInputTransaction(window, callback);
+ }
+ is(notifications.length, 1,
+ description + "Initializing another TIP should cause a notification");
+ is(notifications[0].type, "notify-end-input-transaction",
+ description + "Initializing another TIP should cause \"notify-detached\"");
+ dumpUnexpectedNotifications(1);
+}
+
+async function runFocusNotificationTestAfterDrop() {
+ const inputs = document.querySelectorAll("input[type=text]");
+ inputs[0].value = "abc";
+ inputs[1].value = "";
+
+ const TIP = createTIP();
+ let notifications = [];
+ function callback(aTIP, aNotification)
+ {
+ if (aTIP != TIP) {
+ return true;
+ }
+ switch (aNotification.type) {
+ case "request-to-commit":
+ aTIP.commitComposition();
+ break;
+ case "request-to-cancel":
+ aTIP.cancelComposition();
+ break;
+ case "notify-focus":
+ case "notify-blur":
+ notifications.push(aNotification.type);
+ break;
+ }
+ return true;
+ }
+
+ inputs[0].focus();
+ TIP.beginInputTransactionForTests(window, callback);
+ inputs[0].select();
+ try {
+ notifications = [];
+ await synthesizePlainDragAndDrop({
+ srcSelection: SpecialPowers.wrap(inputs[0]).editor.selection,
+ destElement: inputs[1],
+ });
+ } catch (ex) {
+ ok(false, `runFocusNotificationTestAfterDrop: unexpected error during DnD (${ex.message})`);
+ return;
+ }
+ is(
+ document.activeElement,
+ inputs[1],
+ "runFocusNotificationTestAfterDrop: Dropping to the second <input> should make it focused"
+ );
+ ok(
+ notifications.length > 1,
+ "runFocusNotificationTestAfterDrop: At least two notifications should be fired"
+ );
+ if (notifications.length) {
+ is(
+ notifications[notifications.length - 1],
+ "notify-focus",
+ "runFocusNotificationTestAfterDrop: focus notification should've been fired at last"
+ );
+ }
+}
+
+async function runQuerySelectionEventTestAtTextChangeNotification() {
+ contenteditable.innerHTML = "<p>abc</p><p>def</p>";
+ contenteditable.focus();
+ // Ensure to send notify-focus from IMEContentObserver
+ await new Promise(
+ resolve => requestAnimationFrame(
+ () => requestAnimationFrame(resolve)
+ )
+ );
+ document.execCommand("selectall");
+ // Ensure to send notify-selection-change from IMEContentObserver
+ await new Promise(
+ resolve => requestAnimationFrame(
+ () => requestAnimationFrame(resolve)
+ )
+ );
+
+ const kTestName = "runQuerySelectionEventTestAtTextChangeNotification";
+ await new Promise(resolve => {
+ const TIP = createTIP();
+ TIP.beginInputTransactionForTests(window, (aTIP, aNotification) => {
+ if (aTIP != TIP) {
+ return true;
+ }
+ switch (aNotification.type) {
+ case "request-to-commit":
+ aTIP.commitComposition();
+ break;
+ case "request-to-cancel":
+ aTIP.cancelComposition();
+ break;
+ case "notify-text-change":
+ const textContent = synthesizeQueryTextContent(0, 100);
+ if (textContent?.text.includes("abc")) {
+ break; // Different notification which we want to test, wait next one.
+ }
+ ok(
+ textContent?.succeeded,
+ `${kTestName}: query text content should succeed from notify-text-change handler`
+ );
+ const selectedText = synthesizeQuerySelectedText();
+ ok(
+ selectedText?.succeeded,
+ `${kTestName}: query selected text should succeed from notify-text-change handler`
+ );
+ if (textContent?.succeeded && selectedText?.succeeded) {
+ is(
+ selectedText.text,
+ textContent.text,
+ `${kTestName}: selected text should be same as all text`
+ );
+ }
+ resolve();
+ break;
+ }
+ return true;
+ });
+ // TODO: We want to do this while selection is batched but can flush
+ // pending notifications, however, I have no idea how to do it.
+ contenteditable.firstChild.remove();
+ });
+}
+
+async function runIMEStateUpdateTests() {
+ const TIP = createTIP();
+ let notifications = [];
+ function callback(aTIP, aNotification)
+ {
+ if (aTIP != TIP) {
+ return true;
+ }
+ switch (aNotification.type) {
+ case "request-to-commit":
+ aTIP.commitComposition();
+ break;
+ case "request-to-cancel":
+ aTIP.cancelComposition();
+ break;
+ case "notify-focus":
+ case "notify-blur":
+ notifications.push(aNotification.type);
+ break;
+ }
+ return true;
+ }
+
+ contenteditable.focus();
+ TIP.beginInputTransactionForTests(window, callback);
+ await new Promise(resolve => requestAnimationFrame(() =>
+ requestAnimationFrame(resolve)
+ )); // wait for flushing pending notifications if there is.
+
+ // run IMEStateManager::UpdateIMEState to disable IME
+ notifications = [];
+ const editor = getHTMLEditor(window);
+ editor.flags |= Ci.nsIEditor.eEditorReadonlyMask;
+ await new Promise(resolve => requestAnimationFrame(() =>
+ requestAnimationFrame(resolve)
+ )); // wait for flush pending notification even if handled asynchronously.
+ is(
+ notifications.length ? notifications[0] : undefined,
+ "notify-blur",
+ "runIMEStateUpdateTests: Making the HTMLEditor readonly should cause a blur notification"
+ );
+ is(
+ notifications.length,
+ 1,
+ `runIMEStateUpdateTests: Making the HTMLEditor readonly should not cause any other notifications, but got ${
+ notifications.length > 1 ? notifications[1] : ""
+ } notification`
+ );
+ is(
+ SpecialPowers.getDOMWindowUtils(window)?.IMEStatus,
+ Ci.nsIDOMWindowUtils.IME_STATUS_DISABLED,
+ `runIMEStateUpdateTests: Making the HTMLEditor readonly should make IME disabled`
+ );
+
+ // run IMEStateManager::UpdateIMEState to enable IME
+ notifications = [];
+ editor.flags &= ~Ci.nsIEditor.eEditorReadonlyMask;
+ await new Promise(resolve => requestAnimationFrame(() =>
+ requestAnimationFrame(resolve)
+ )); // wait for flush pending notification even if handled asynchronously.
+ is(
+ notifications.length ? notifications[0] : undefined,
+ "notify-focus",
+ "runIMEStateUpdateTests: Making the HTMLEditor editable should cause a focus notification without blur notification"
+ );
+ is(
+ notifications.length,
+ 1,
+ `runIMEStateUpdateTests: Making the HTMLEditor editable should not cause any other notifications, but got ${
+ notifications.length > 1 ? notifications[1] : ""
+ } notification`
+ );
+ is(
+ SpecialPowers.getDOMWindowUtils(window)?.IMEStatus,
+ Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED,
+ `runIMEStateUpdateTests: Making the HTMLEditor readonly should make IME disabled`
+ );
+}
+
+async function runTextNotificationChangesDuringNoFrame() {
+ const TIP = createTIP();
+ let onTextChange;
+ function callback(aTIP, aNotification)
+ {
+ if (aTIP != TIP) {
+ return true;
+ }
+ switch (aNotification.type) {
+ case "request-to-commit":
+ aTIP.commitComposition();
+ break;
+ case "request-to-cancel":
+ aTIP.cancelComposition();
+ break;
+ case "notify-text-change":
+ if (onTextChange) {
+ onTextChange(aNotification);
+ }
+ break;
+ }
+ return true;
+ }
+
+ function promiseTextChangeNotification() {
+ return new Promise(resolve => onTextChange = resolve);
+ }
+
+ function waitForTick() {
+ return new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
+ }
+
+ const input = document.querySelector("input[type=text]");
+ input.focus();
+ TIP.beginInputTransactionForTests(window, callback);
+
+ await (async function test_text_change_notification_for_value_set_during_no_frame() {
+ const description = "runTextNotificationChangesDuringNoFrame: test_text_change_notification_for_value_set_during_no_frame";
+ input.value = "Start";
+ input.style.display = "inline";
+ input.getBoundingClientRect();
+ await waitForTick();
+ const waitNotifications = promiseTextChangeNotification();
+ input.style.display = "block";
+ input.value = "Changed";
+ info(`${description}: waiting for notifications...`);
+ const notification = await waitNotifications;
+ is(
+ notification?.offset,
+ 0,
+ `${description}: offset should be 0`
+ );
+ is(
+ notification?.removedLength,
+ "Start".length,
+ `${description}: removedLength should be the length of the old value`
+ );
+ is(
+ notification?.addedLength,
+ "Changed".length,
+ `${description}: addedLength should be the length of the new value`
+ );
+ })();
+
+ await (async function test_text_change_notification_for_multiple_value_set_during_no_frame() {
+ const description = "runTextNotificationChangesDuringNoFrame: test_text_change_notification_for_multiple_value_set_during_no_frame";
+ input.value = "Start";
+ input.style.display = "inline";
+ input.getBoundingClientRect();
+ await waitForTick();
+ const waitNotifications = promiseTextChangeNotification();
+ input.style.display = "block";
+ input.value = "Changed";
+ input.value = "Again!";
+ info(`${description}: waiting for notifications...`);
+ const notification = await waitNotifications;
+ is(
+ notification?.offset,
+ 0,
+ `${description}: offset should be 0`
+ );
+ is(
+ notification?.removedLength,
+ "Start".length,
+ `${description}: removedLength should be the length of the old value`
+ );
+ is(
+ notification?.addedLength,
+ "Again!".length,
+ `${description}: addedLength should be the length of the new value`
+ );
+ })();
+
+ await (async function test_text_change_notification_for_value_set_and_typing_character_during_no_frame() {
+ const description = "runTextNotificationChangesDuringNoFrame: test_text_change_notification_for_value_set_and_typing_character_during_no_frame";
+ input.value = "Start";
+ input.style.display = "inline";
+ input.getBoundingClientRect();
+ await waitForTick();
+ const waitNotifications = promiseTextChangeNotification();
+ input.style.display = "block";
+ input.value = "Change";
+ const dKey = new KeyboardEvent("", { code: "KeyD", key: "d", keyCode: KeyboardEvent.DOM_VK_D });
+ TIP.keydown(dKey);
+ TIP.keyup(dKey);
+ info(`${description}: waiting for notifications...`);
+ const notification = await waitNotifications;
+ is(
+ notification?.offset,
+ 0,
+ `${description}: offset should be 0`
+ );
+ is(
+ notification?.removedLength,
+ "Start".length,
+ `${description}: removedLength should be the length of the old value`
+ );
+ is(
+ notification?.addedLength,
+ "Change".length,
+ `${description}: addedLength should be the length of the new (set) value`
+ );
+ })();
+
+ input.style.display = "";
+
+ textarea.focus();
+ TIP.beginInputTransaction(window, callback);
+
+ await (async function test_text_change_notification_for_multi_line_value_set_during_no_frame() {
+ const description = "runTextNotificationChangesDuringNoFrame: test_text_change_notification_for_multi_line_value_set_during_no_frame";
+ textarea.value = "Start\n2nd Line";
+ textarea.style.display = "inline";
+ textarea.getBoundingClientRect();
+ await waitForTick();
+ const waitNotifications = promiseTextChangeNotification();
+ textarea.style.display = "block";
+ textarea.value = "Changed\n2nd Line";
+ info(`${description}: waiting for notifications...`);
+ const notification = await waitNotifications;
+ is(
+ notification?.offset,
+ 0,
+ `${description}: offset should be 0`
+ );
+ is(
+ notification?.removedLength,
+ getNativeText("Start\n2nd Line").length,
+ `${description}: removedLength should be the length of the old value`
+ );
+ is(
+ notification?.addedLength,
+ getNativeText("Changed\n2nd Line").length,
+ `${description}: addedLength should be the length of the new value`
+ );
+ })();
+
+ textarea.style.display = "";
+}
+
+async function runTests()
+{
+ textareaInFrame = iframe.contentDocument.getElementById("textarea");
+ runBeginInputTransactionMethodTests();
+ runReleaseTests();
+ runCompositionTests();
+ runCompositionWithKeyEventTests();
+ runConsumingKeydownBeforeCompositionTests();
+ runKeyTests();
+ runErrorTests();
+ runCommitCompositionTests();
+ await runCallbackTests(false);
+ await runCallbackTests(true);
+ await runTextNotificationChangesDuringNoFrame();
+ await runFocusNotificationTestAfterDrop();
+ await runUnloadTests1();
+ await runUnloadTests2();
+ await runQuerySelectionEventTestAtTextChangeNotification();
+ await runIMEStateUpdateTests();
+
+ finish();
+}
+
+]]>
+</script>
+
+</window>
diff --git a/dom/base/test/chrome/window_swapFrameLoaders.xhtml b/dom/base/test/chrome/window_swapFrameLoaders.xhtml
new file mode 100644
index 0000000000..0a42e975fc
--- /dev/null
+++ b/dom/base/test/chrome/window_swapFrameLoaders.xhtml
@@ -0,0 +1,225 @@
+<?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=1242644
+Test swapFrameLoaders with different frame types and remoteness
+-->
+<window title="Mozilla Bug 1242644"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"><![CDATA[
+ ["SimpleTest", "SpecialPowers", "info", "is", "ok", "add_task"].forEach(key => {
+ window[key] = window.arguments[0][key];
+ })
+
+ const NS = {
+ xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+ html: "http://www.w3.org/1999/xhtml",
+ }
+
+ const TAG = {
+ xul: "browser",
+ html: "iframe", // mozbrowser
+ }
+
+ const SCENARIOS = [
+ ["xul", "xul"],
+ ["xul", "html"],
+ ["html", "xul"],
+ ["html", "html"],
+ ["xul", "xul", { remote: true }],
+ ["xul", "html", { remote: true }],
+ ["html", "xul", { remote: true }],
+ ["html", "html", { remote: true }],
+ ["xul", "html", { userContextId: 2 }],
+ ["xul", "html", { userContextId: 2, remote: true }],
+ ];
+
+ const HEIGHTS = [
+ 200,
+ 400
+ ];
+
+ function frameScript() {
+ /* eslint-env mozilla/frame-script */
+ addEventListener("load", function onLoad() {
+ sendAsyncMessage("test:load");
+ }, true);
+ }
+
+ // Watch for loads in new frames
+ window.messageManager.loadFrameScript(`data:,(${frameScript})();`, true);
+
+ function once(target, eventName, useCapture = false) {
+ info("Waiting for event: '" + eventName + "' on " + target + ".");
+
+ return new Promise(resolve => {
+ for (let [add, remove] of [
+ ["addEventListener", "removeEventListener"],
+ ["addMessageListener", "removeMessageListener"],
+ ]) {
+ if ((add in target) && (remove in target)) {
+ target[add](eventName, function onEvent(...aArgs) {
+ info("Got event: '" + eventName + "' on " + target + ".");
+ target[remove](eventName, onEvent, useCapture);
+ resolve(aArgs);
+ }, useCapture);
+ break;
+ }
+ }
+ });
+ }
+
+ async function addFrame(type, options, height) {
+ let remote = options && options.remote;
+ let userContextId = options && options.userContextId;
+ let frame = document.createElementNS(NS[type], TAG[type]);
+ frame.setAttribute("remote", remote);
+ if (remote && type == "xul") {
+ frame.setAttribute("style", "-moz-binding: none;");
+ }
+ if (userContextId) {
+ frame.setAttribute("usercontextid", userContextId);
+ }
+ if (type == "html") {
+ frame.setAttribute("mozbrowser", "true");
+ frame.setAttribute("noisolation", "true");
+ frame.setAttribute("allowfullscreen", "true");
+ } else if (type == "xul") {
+ frame.setAttribute("type", "content");
+ }
+ let src = `data:text/html,<!doctype html>` +
+ `<body style="height:${height}px"/>`;
+ frame.setAttribute("src", src);
+ document.documentElement.appendChild(frame);
+ let mm = frame.frameLoader.messageManager;
+ await once(mm, "test:load");
+ return frame;
+ }
+
+ add_task(async function() {
+ for (let scenario of SCENARIOS) {
+ let [ typeA, typeB, options ] = scenario;
+ let heightA = HEIGHTS[0];
+ info(`Adding frame A, type ${typeA}, options ${JSON.stringify(options)}, height ${heightA}`);
+ let frameA = await addFrame(typeA, options, heightA);
+
+ let heightB = HEIGHTS[1];
+ info(`Adding frame B, type ${typeB}, options ${JSON.stringify(options)}, height ${heightB}`);
+ let frameB = await addFrame(typeB, options, heightB);
+
+ let frameScriptFactory = function(name) {
+ /* eslint-env mozilla/frame-script */
+ return `function() {
+ addMessageListener("ping", function() {
+ sendAsyncMessage("pong", "${name}");
+ });
+ addMessageListener("check-browser-api", function() {
+ let exists = "api" in this;
+ sendAsyncMessage("check-browser-api", {
+ exists,
+ running: exists && !this.api._shuttingDown,
+ });
+ });
+ addEventListener("pagehide", function({ inFrameSwap }) {
+ sendAsyncMessage("pagehide", inFrameSwap);
+ }, {mozSystemGroup: true});
+ }`;
+ }
+
+ // Load frame script into each frame
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ mmA.loadFrameScript("data:,(" + frameScriptFactory("A") + ")()", false);
+ mmB.loadFrameScript("data:,(" + frameScriptFactory("B") + ")()", false);
+ }
+
+ // Ping before swap
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ let inflightA = once(mmA, "pong");
+ let inflightB = once(mmB, "pong");
+
+ info("Ping message manager for frame A");
+ mmA.sendAsyncMessage("ping");
+ let [ { data: pongA } ] = await inflightA;
+ is(pongA, "A", "Frame A message manager gets reply A before swap");
+
+ info("Ping message manager for frame B");
+ mmB.sendAsyncMessage("ping");
+ let [ { data: pongB } ] = await inflightB;
+ is(pongB, "B", "Frame B message manager gets reply B before swap");
+ }
+
+ // Ping after swap using message managers acquired before
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ let pagehideA = once(mmA, "pagehide");
+ let pagehideB = once(mmB, "pagehide");
+
+ info("swapFrameLoaders");
+ frameA.swapFrameLoaders(frameB);
+
+ let [ { data: inFrameSwapA } ] = await pagehideA;
+ ok(inFrameSwapA, "Frame A got pagehide with inFrameSwap: true");
+ let [ { data: inFrameSwapB } ] = await pagehideB;
+ ok(inFrameSwapB, "Frame B got pagehide with inFrameSwap: true");
+
+ let inflightA = once(mmA, "pong");
+ let inflightB = once(mmB, "pong");
+
+ info("Ping message manager for frame A");
+ mmA.sendAsyncMessage("ping");
+ let [ { data: pongA } ] = await inflightA;
+ is(pongA, "B", "Frame A message manager acquired before swap gets reply B after swap");
+
+ info("Ping message manager for frame B");
+ mmB.sendAsyncMessage("ping");
+ let [ { data: pongB } ] = await inflightB;
+ is(pongB, "A", "Frame B message manager acquired before swap gets reply A after swap");
+ }
+
+ // Check height after swap
+ {
+ if (frameA.getContentDimensions) {
+ let { height } = await frameA.getContentDimensions();
+ is(height, heightB, "Frame A's content height is 400px after swap");
+ }
+ if (frameB.getContentDimensions) {
+ let { height } = await frameB.getContentDimensions();
+ is(height, heightA, "Frame B's content height is 200px after swap");
+ }
+ }
+
+ // Ping after swap using message managers acquired after
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ let inflightA = once(mmA, "pong");
+ let inflightB = once(mmB, "pong");
+
+ info("Ping message manager for frame A");
+ mmA.sendAsyncMessage("ping");
+ let [ { data: pongA } ] = await inflightA;
+ is(pongA, "B", "Frame A message manager acquired after swap gets reply B after swap");
+
+ info("Ping message manager for frame B");
+ mmB.sendAsyncMessage("ping");
+ let [ { data: pongB } ] = await inflightB;
+ is(pongB, "A", "Frame B message manager acquired after swap gets reply A after swap");
+ }
+
+ frameA.remove();
+ frameB.remove();
+ }
+ });
+ ]]></script>
+</window>
diff --git a/dom/base/test/common_postMessages.js b/dom/base/test/common_postMessages.js
new file mode 100644
index 0000000000..e582adb41f
--- /dev/null
+++ b/dom/base/test/common_postMessages.js
@@ -0,0 +1,393 @@
+function getType(a) {
+ if (a === null || a === undefined) {
+ return "null";
+ }
+
+ if (Array.isArray(a)) {
+ return "array";
+ }
+
+ if (typeof a == "object") {
+ return "object";
+ }
+
+ if (
+ SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported() &&
+ a instanceof WebAssembly.Module
+ ) {
+ return "wasm";
+ }
+
+ return "primitive";
+}
+
+function compare(a, b) {
+ is(getType(a), getType(b), "Type matches");
+
+ var type = getType(a);
+ if (type == "array") {
+ is(a.length, b.length, "Array.length matches");
+ for (var i = 0; i < a.length; ++i) {
+ compare(a[i], b[i]);
+ }
+
+ return;
+ }
+
+ if (type == "object") {
+ ok(a !== b, "They should not match");
+
+ var aProps = [];
+ for (var p in a) {
+ aProps.push(p);
+ }
+
+ var bProps = [];
+ for (var p in b) {
+ bProps.push(p);
+ }
+
+ is(aProps.length, bProps.length, "Props match");
+ is(aProps.sort().toString(), bProps.sort().toString(), "Props names match");
+
+ for (var p in a) {
+ compare(a[p], b[p]);
+ }
+
+ return;
+ }
+
+ if (type == "wasm") {
+ var wasmA = new WebAssembly.Instance(a);
+ ok(wasmA instanceof WebAssembly.Instance, "got an instance");
+
+ var wasmB = new WebAssembly.Instance(b);
+ ok(wasmB instanceof WebAssembly.Instance, "got an instance");
+
+ ok(wasmA.exports.foo() === wasmB.exports.foo(), "Same result!");
+ ok(wasmB.exports.foo() === 42, "We want 42");
+ }
+
+ if (type != "null") {
+ is(a, b, "Same value");
+ }
+}
+
+var clonableObjects = [
+ { target: "all", data: "hello world" },
+ { target: "all", data: 123 },
+ { target: "all", data: null },
+ { target: "all", data: true },
+ { target: "all", data: new Date() },
+ { target: "all", data: [1, "test", true, new Date()] },
+ {
+ target: "all",
+ data: { a: true, b: null, c: new Date(), d: [true, false, {}] },
+ },
+ { target: "all", data: new Blob([123], { type: "plain/text" }) },
+ { target: "all", data: new ImageData(2, 2) },
+];
+
+function create_fileList() {
+ var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
+ var script = SpecialPowers.loadChromeScript(url);
+
+ function onOpened(message) {
+ var fileList = document.getElementById("fileList");
+ SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
+
+ // Just a simple test
+ var domFile = fileList.files[0];
+ is(domFile.name, "prefs.js", "fileName should be prefs.js");
+
+ clonableObjects.push({ target: "all", data: fileList.files });
+ script.destroy();
+ next();
+ }
+
+ script.addMessageListener("file.opened", onOpened);
+ script.sendAsyncMessage("file.open");
+}
+
+function create_directory() {
+ if (navigator.userAgent.toLowerCase().includes("Android")) {
+ next();
+ return;
+ }
+
+ var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
+ var script = SpecialPowers.loadChromeScript(url);
+
+ function onOpened(message) {
+ var fileList = document.getElementById("fileList");
+ SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
+
+ SpecialPowers.wrap(fileList)
+ .getFilesAndDirectories()
+ .then(function (list) {
+ list = SpecialPowers.unwrap(list);
+ // Just a simple test
+ is(list.length, 1, "This list has 1 element");
+ ok(list[0] instanceof Directory, "We have a directory.");
+
+ clonableObjects.push({ target: "all", data: list[0] });
+ script.destroy();
+ next();
+ });
+ }
+
+ script.addMessageListener("dir.opened", onOpened);
+ script.sendAsyncMessage("dir.open");
+}
+
+function create_wasmModule() {
+ info("Checking if we can play with WebAssembly...");
+
+ if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) {
+ next();
+ return;
+ }
+
+ ok(WebAssembly, "WebAssembly object should exist");
+ ok(WebAssembly.compile, "WebAssembly.compile function should exist");
+
+ /*
+ js -e '
+ t = wasmTextToBinary(`
+ (module
+ (func $foo (result i32) (i32.const 42))
+ (export "foo" (func $foo))
+ )
+ `);
+ print(t)
+ '
+ */
+ // prettier-ignore
+ const fooModuleCode = new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,7,7,1,3,102,111,111,0,0,10,6,1,4,0,65,42,11,0,13,4,110,97,109,101,1,6,1,0,3,102,111,111]);
+
+ WebAssembly.compile(fooModuleCode).then(
+ m => {
+ ok(m instanceof WebAssembly.Module, "The WasmModule has been compiled.");
+ clonableObjects.push({ target: "sameProcess", data: m });
+ next();
+ },
+ () => {
+ ok(false, "The compilation of the wasmModule failed.");
+ }
+ );
+}
+
+function runTests(obj) {
+ ok(
+ "clonableObjectsEveryWhere" in obj &&
+ "clonableObjectsSameProcess" in obj &&
+ "transferableObjects" in obj &&
+ (obj.clonableObjectsEveryWhere ||
+ obj.clonableObjectsSameProcess ||
+ obj.transferableObjects),
+ "We must run some test!"
+ );
+
+ // cloning tests - everyWhere
+ new Promise(function (resolve, reject) {
+ var clonableObjectsId = 0;
+ function runClonableTest() {
+ if (clonableObjectsId >= clonableObjects.length) {
+ resolve();
+ return;
+ }
+
+ var object = clonableObjects[clonableObjectsId++];
+
+ if (object.target != "all") {
+ runClonableTest();
+ return;
+ }
+
+ obj
+ .send(object.data, [])
+ .catch(() => {
+ return { error: true };
+ })
+ .then(received => {
+ if (!obj.clonableObjectsEveryWhere) {
+ ok(received.error, "Error expected");
+ } else {
+ ok(!received.error, "Error not expected");
+ compare(received.data, object.data);
+ }
+ runClonableTest();
+ });
+ }
+
+ runClonableTest();
+ })
+
+ // clonable same process
+ .then(function () {
+ return new Promise(function (resolve, reject) {
+ var clonableObjectsId = 0;
+ function runClonableTest() {
+ if (clonableObjectsId >= clonableObjects.length) {
+ resolve();
+ return;
+ }
+
+ var object = clonableObjects[clonableObjectsId++];
+
+ if (object.target != "sameProcess") {
+ runClonableTest();
+ return;
+ }
+
+ obj
+ .send(object.data, [])
+ .catch(() => {
+ return { error: true };
+ })
+ .then(received => {
+ if (!obj.clonableObjectsSameProcess) {
+ ok(received.error, "Error expected");
+ } else {
+ ok(!received.error, "Error not expected");
+ compare(received.data, object.data);
+ }
+ runClonableTest();
+ });
+ }
+
+ runClonableTest();
+ });
+ })
+
+ // transfering tests
+ .then(function () {
+ if (!obj.transferableObjects) {
+ return;
+ }
+
+ // MessagePort
+ return new Promise(function (r, rr) {
+ var mc = new MessageChannel();
+ obj.send(42, [mc.port1]).then(function (received) {
+ is(received.ports.length, 1, "MessagePort has been transferred");
+ mc.port2.postMessage("hello world");
+ received.ports[0].onmessage = function (e) {
+ is(e.data, "hello world", "Ports are connected!");
+ r();
+ };
+ });
+ });
+ })
+
+ // no dup transfering
+ .then(function () {
+ if (!obj.transferableObjects) {
+ return;
+ }
+
+ // MessagePort
+ return new Promise(function (r, rr) {
+ var mc = new MessageChannel();
+ obj
+ .send(42, [mc.port1, mc.port1])
+ .then(
+ function (received) {
+ ok(false, "Duplicate ports should throw!");
+ },
+ function () {
+ ok(true, "Duplicate ports should throw!");
+ }
+ )
+ .then(r);
+ });
+ })
+
+ // maintaining order of transferred ports
+ .then(function () {
+ if (!obj.transferableObjects) {
+ return;
+ }
+
+ // MessagePort
+ return new Promise(function (r, rr) {
+ var mcs = [];
+ const NPORTS = 50;
+ for (let i = 0; i < NPORTS; i++) {
+ mcs.push(new MessageChannel());
+ }
+ obj
+ .send(
+ 42,
+ mcs.map(channel => channel.port1)
+ )
+ .then(function (received) {
+ is(
+ received.ports.length,
+ NPORTS,
+ `all ${NPORTS} ports transferred`
+ );
+ const promises = Array(NPORTS)
+ .fill()
+ .map(
+ (_, i) =>
+ new Promise(function (subr, subrr) {
+ mcs[i].port2.postMessage(i);
+ received.ports[i].onmessage = e => subr(e.data == i);
+ })
+ );
+ return Promise.all(promises);
+ })
+ .then(function (result) {
+ let in_order = 0;
+ for (const correct of result) {
+ if (correct) {
+ in_order++;
+ }
+ }
+ is(in_order, NPORTS, "All transferred ports are in order");
+ })
+ .then(r);
+ });
+ })
+
+ // non transfering tests
+ .then(function () {
+ if (obj.transferableObjects) {
+ return;
+ }
+
+ // MessagePort
+ return new Promise(function (r, rr) {
+ var mc = new MessageChannel();
+ obj
+ .send(42, [mc.port1])
+ .then(
+ function (received) {
+ ok(false, "This object should not support port transferring");
+ },
+ function () {
+ ok(true, "This object should not support port transferring");
+ }
+ )
+ .then(r);
+ });
+ })
+
+ // done.
+ .then(function () {
+ obj.finished();
+ });
+}
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+var tests = [create_fileList, create_directory, create_wasmModule];
diff --git a/dom/base/test/copypaste.js b/dom/base/test/copypaste.js
new file mode 100644
index 0000000000..01ec2da1b9
--- /dev/null
+++ b/dom/base/test/copypaste.js
@@ -0,0 +1,553 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function modifySelection(s) {
+ var g = window.getSelection();
+ var l = g.getRangeAt(0);
+ var d = document.createElement("p");
+ d.innerHTML = s;
+ d.appendChild(l.cloneContents());
+
+ var e = document.createElement("div");
+ document.body.appendChild(e);
+ e.appendChild(d);
+ var a = document.createRange();
+ a.selectNode(d);
+ g.removeAllRanges();
+ g.addRange(a);
+ window.setTimeout(function () {
+ e.remove();
+ g.removeAllRanges();
+ g.addRange(l);
+ }, 0);
+}
+
+function getLoadContext() {
+ var Ci = SpecialPowers.Ci;
+ return SpecialPowers.wrap(window).docShell.QueryInterface(Ci.nsILoadContext);
+}
+
+async function testCopyPaste(isXHTML) {
+ var suppressUnicodeCheckIfHidden = !!isXHTML;
+ var suppressHTMLCheck = !!isXHTML;
+
+ var docShell = SpecialPowers.wrap(window).docShell;
+
+ var documentViewer = docShell.contentViewer.QueryInterface(
+ SpecialPowers.Ci.nsIContentViewerEdit
+ );
+
+ var clipboard = SpecialPowers.Services.clipboard;
+
+ var textarea = SpecialPowers.wrap(document.getElementById("input"));
+
+ async function copySelectionToClipboard(suppressUnicodeCheck) {
+ await SimpleTest.promiseClipboardChange(
+ () => true,
+ () => {
+ documentViewer.copySelection();
+ }
+ );
+ if (!suppressUnicodeCheck) {
+ ok(
+ clipboard.hasDataMatchingFlavors(["text/plain"], 1),
+ "check text/plain"
+ );
+ }
+ if (!suppressHTMLCheck) {
+ ok(clipboard.hasDataMatchingFlavors(["text/html"], 1), "check text/html");
+ }
+ }
+ function clear(node, suppressUnicodeCheck) {
+ textarea.blur();
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ }
+ async function copyToClipboard(node, suppressUnicodeCheck) {
+ clear();
+ var r = document.createRange();
+ r.selectNode(node);
+ window.getSelection().addRange(r);
+ await copySelectionToClipboard(suppressUnicodeCheck);
+ }
+ function addRange(startNode, startIndex, endNode, endIndex) {
+ var sel = window.getSelection();
+ var r = document.createRange();
+ r.setStart(startNode, startIndex);
+ r.setEnd(endNode, endIndex);
+ sel.addRange(r);
+ }
+ async function copyRangeToClipboard(
+ startNode,
+ startIndex,
+ endNode,
+ endIndex,
+ suppressUnicodeCheck
+ ) {
+ clear();
+ addRange(startNode, startIndex, endNode, endIndex);
+ await copySelectionToClipboard(suppressUnicodeCheck);
+ }
+ async function copyChildrenToClipboard(id) {
+ clear();
+ window.getSelection().selectAllChildren(document.getElementById(id));
+ await copySelectionToClipboard();
+ }
+ function getClipboardData(mime) {
+ var transferable = SpecialPowers.Cc[
+ "@mozilla.org/widget/transferable;1"
+ ].createInstance(SpecialPowers.Ci.nsITransferable);
+ transferable.init(getLoadContext());
+ transferable.addDataFlavor(mime);
+ clipboard.getData(transferable, 1);
+ var data = SpecialPowers.createBlankObject();
+ transferable.getTransferData(mime, data);
+ return data;
+ }
+ function testHtmlClipboardValue(mime, expected) {
+ // For Windows, navigator.platform returns "Win32".
+ var expectedValue = expected;
+ if (navigator.platform.includes("Win")) {
+ // Windows has extra content.
+ var expectedValue =
+ kTextHtmlPrefixClipboardDataWindows +
+ expected.replace(/\n/g, "\n") +
+ kTextHtmlSuffixClipboardDataWindows;
+ }
+ testClipboardValue(mime, expectedValue);
+ }
+ function testClipboardValue(mime, expected) {
+ if (suppressHTMLCheck && mime == "text/html") {
+ return null;
+ }
+ var data = SpecialPowers.wrap(getClipboardData(mime));
+ is(
+ data.value == null
+ ? data.value
+ : data.value.QueryInterface(SpecialPowers.Ci.nsISupportsString).data,
+ expected,
+ mime + " value in the clipboard"
+ );
+ return data.value;
+ }
+ function testPasteText(expected) {
+ textarea.value = "";
+ textarea.focus();
+ textarea.editor.paste(1);
+ is(textarea.value, expected, "value of the textarea after the paste");
+ }
+ function testPasteHTML(id, expected) {
+ var contentEditable = $(id);
+ contentEditable.focus();
+ synthesizeKey("v", { accelKey: true });
+ is(contentEditable.innerHTML, expected, id + ".innerHtml after the paste");
+ }
+ function testSelectionToString(expected) {
+ is(
+ window.getSelection().toString().replace(/\r\n/g, "\n"),
+ expected,
+ "Selection.toString"
+ );
+ }
+ function testInnerHTML(id, expected) {
+ var value = document.getElementById(id).innerHTML;
+ is(value, expected, id + ".innerHTML");
+ }
+
+ await copyChildrenToClipboard("draggable");
+ testSelectionToString("This is a draggable bit of text.");
+ testClipboardValue("text/plain", "This is a draggable bit of text.");
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="draggable" title="title to have a long HTML line">This is a <em>draggable</em> bit of text.</div>'
+ );
+ testPasteText("This is a draggable bit of text.");
+
+ await copyChildrenToClipboard("alist");
+ testSelectionToString(" bla\n\n foo\n bar\n\n");
+ testClipboardValue("text/plain", " bla\n\n foo\n bar\n\n");
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="alist">\n bla\n <ul>\n <li>foo</li>\n \n <li>bar</li>\n </ul>\n </div>'
+ );
+ testPasteText(" bla\n\n foo\n bar\n\n");
+
+ await copyChildrenToClipboard("blist");
+ testSelectionToString(" mozilla\n\n foo\n bar\n\n");
+ testClipboardValue("text/plain", " mozilla\n\n foo\n bar\n\n");
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="blist">\n mozilla\n <ol>\n <li>foo</li>\n \n <li>bar</li>\n </ol>\n </div>'
+ );
+ testPasteText(" mozilla\n\n foo\n bar\n\n");
+
+ await copyChildrenToClipboard("clist");
+ testSelectionToString(" mzla\n\n foo\n bazzinga!\n bar\n\n");
+ testClipboardValue(
+ "text/plain",
+ " mzla\n\n foo\n bazzinga!\n bar\n\n"
+ );
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="clist">\n mzla\n <ul>\n <li>foo<ul>\n <li>bazzinga!</li>\n </ul></li>\n \n <li>bar</li>\n </ul>\n </div>'
+ );
+ testPasteText(" mzla\n\n foo\n bazzinga!\n bar\n\n");
+
+ await copyChildrenToClipboard("div4");
+ testSelectionToString(" Tt t t ");
+ testClipboardValue("text/plain", " Tt t t ");
+ if (isXHTML) {
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="div4">\n T<textarea xmlns="http://www.w3.org/1999/xhtml">t t t</textarea>\n</div>'
+ );
+ testInnerHTML(
+ "div4",
+ '\n T<textarea xmlns="http://www.w3.org/1999/xhtml">t t t</textarea>\n'
+ );
+ } else {
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="div4">\n T<textarea>t t t</textarea>\n</div>'
+ );
+ testInnerHTML("div4", "\n T<textarea>t t t</textarea>\n");
+ }
+ testPasteText(" Tt t t ");
+
+ await copyChildrenToClipboard("div5");
+ testSelectionToString(" T ");
+ testClipboardValue("text/plain", " T ");
+ if (isXHTML) {
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="div5">\n T<textarea xmlns="http://www.w3.org/1999/xhtml"> </textarea>\n</div>'
+ );
+ testInnerHTML(
+ "div5",
+ '\n T<textarea xmlns="http://www.w3.org/1999/xhtml"> </textarea>\n'
+ );
+ } else {
+ testHtmlClipboardValue(
+ "text/html",
+ '<div id="div5">\n T<textarea> </textarea>\n</div>'
+ );
+ testInnerHTML("div5", "\n T<textarea> </textarea>\n");
+ }
+ testPasteText(" T ");
+
+ await copyRangeToClipboard(
+ $("div6").childNodes[0],
+ 0,
+ $("div6").childNodes[1],
+ 1,
+ suppressUnicodeCheckIfHidden
+ );
+ testSelectionToString("");
+ // START Disabled due to bug 564688
+ if (false) {
+ testClipboardValue("text/plain", "");
+ testClipboardValue("text/html", "");
+ }
+ // END Disabled due to bug 564688
+ testInnerHTML("div6", "div6");
+
+ await copyRangeToClipboard(
+ $("div7").childNodes[0],
+ 0,
+ $("div7").childNodes[0],
+ 4,
+ suppressUnicodeCheckIfHidden
+ );
+ testSelectionToString("");
+ // START Disabled due to bug 564688
+ if (false) {
+ testClipboardValue("text/plain", "");
+ testClipboardValue("text/html", "");
+ }
+ // END Disabled due to bug 564688
+ testInnerHTML("div7", "div7");
+
+ await copyRangeToClipboard(
+ $("div8").childNodes[0],
+ 0,
+ $("div8").childNodes[0],
+ 4,
+ suppressUnicodeCheckIfHidden
+ );
+ testSelectionToString("");
+ // START Disabled due to bug 564688
+ if (false) {
+ testClipboardValue("text/plain", "");
+ testClipboardValue("text/html", "");
+ }
+ // END Disabled due to bug 564688
+ testInnerHTML("div8", "div8");
+
+ await copyRangeToClipboard(
+ $("div9").childNodes[0],
+ 0,
+ $("div9").childNodes[0],
+ 4,
+ suppressUnicodeCheckIfHidden
+ );
+ testSelectionToString("div9");
+ testClipboardValue("text/plain", "div9");
+ testHtmlClipboardValue("text/html", "div9");
+ testInnerHTML("div9", "div9");
+
+ await copyToClipboard($("div10"), suppressUnicodeCheckIfHidden);
+ testSelectionToString("");
+ testInnerHTML("div10", "div10");
+
+ await copyToClipboard($("div10").firstChild, suppressUnicodeCheckIfHidden);
+ testSelectionToString("");
+
+ await copyRangeToClipboard(
+ $("div10").childNodes[0],
+ 0,
+ $("div10").childNodes[0],
+ 1,
+ suppressUnicodeCheckIfHidden
+ );
+ testSelectionToString("");
+
+ await copyRangeToClipboard(
+ $("div10").childNodes[1],
+ 0,
+ $("div10").childNodes[1],
+ 1,
+ suppressUnicodeCheckIfHidden
+ );
+ testSelectionToString("");
+
+ if (!isXHTML) {
+ // ============ copy/paste multi-range selection (bug 1123505)
+ // with text start node
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ var r = document.createRange();
+ var ul = $("ul1");
+ var parent = ul.parentNode;
+ r.setStart(parent, 0);
+ r.setEnd(parent.firstChild, 15);
+ sel.addRange(r); // <div>{Copy1then Paste]<ul id="ul1"><li>LI</li>\n</ul></div>
+
+ r = document.createRange();
+ r.setStart(ul, 1);
+ r.setEnd(parent, 2);
+ sel.addRange(r); // <div>Copy1then Paste<ul id="ul1"><li>LI{</li>\n</ul>}</div>
+ await copySelectionToClipboard(true);
+ testPasteHTML("contentEditable1", "Copy1then Paste"); // The <ul> should not appear because it has no <li>s
+
+ // with text end node
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ var r = document.createRange();
+ var ul = $("ul2");
+ var parent = ul.parentNode;
+ r.setStart(parent, 0);
+ r.setEnd(ul, 1);
+ sel.addRange(r); // <div>{<ul id="ul2">\n}<li>LI</li></ul>Copy2then Paste</div>
+
+ r = document.createRange();
+ r.setStart(parent.childNodes[1], 0);
+ r.setEnd(parent, 2);
+ sel.addRange(r); // <div><ul id="ul2">\n<li>LI</li></ul>[Copy2then Paste}</div>
+ await copySelectionToClipboard(true);
+ testPasteHTML("contentEditable2", "Copy2then Paste"); // The <ul> should not appear because it has no <li>s
+
+ // with text end node and non-empty start
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ var r = document.createRange();
+ var ul = $("ul3");
+ var parent = ul.parentNode;
+ r.setStart(parent, 0);
+ r.setEnd(ul, 1);
+ sel.addRange(r); // <div>{<ul id="ul3"><li>\n</li>}<li>LI</li></ul>Copy3then Paste</div>
+
+ r = document.createRange();
+ r.setStart(parent.childNodes[1], 0);
+ r.setEnd(parent, 2);
+ sel.addRange(r); // <div><ul id="ul3"><li>\n</li><li>LI</li></ul>[Copy3then Paste}</div>
+ await copySelectionToClipboard(true);
+ testPasteHTML(
+ "contentEditable3",
+ '<ul id="ul3"><li>\n<br></li></ul>Copy3then Paste' // The <ul> should appear because it has a <li>
+ );
+
+ // with elements of different depth
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ var r = document.createRange();
+ var div1 = $("div1s");
+ var parent = div1.parentNode;
+ r.setStart(parent, 0);
+ r.setEnd(document.getElementById("div1se1"), 1); // after the "inner" DIV
+ sel.addRange(r);
+
+ r = document.createRange();
+ r.setStart(div1.childNodes[1], 0); // the start of "after"
+ r.setEnd(parent, 1);
+ sel.addRange(r);
+ await copySelectionToClipboard(true);
+ testPasteHTML(
+ "contentEditable4",
+ '<div id="div1s"><div id="div1se1">before</div></div><div id="div1s">after</div>'
+ );
+
+ // with elements of different depth, and a text node at the end
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ var r = document.createRange();
+ var div1 = $("div2s");
+ var parent = div1.parentNode;
+ r.setStart(parent, 0);
+ r.setEnd(document.getElementById("div2se1"), 1); // after the "inner" DIV
+ sel.addRange(r);
+
+ r = document.createRange();
+ r.setStart(div1.childNodes[1], 0); // the start of "after"
+ r.setEnd(parent, 1);
+ sel.addRange(r);
+ await copySelectionToClipboard(true);
+ testPasteHTML(
+ "contentEditable5",
+ '<div id="div2s"><div id="div2se1">before</div></div><div id="div2s">after</div>'
+ );
+
+ // crash test for bug 1127835
+ var e1 = document.getElementById("1127835crash1");
+ var e2 = document.getElementById("1127835crash2");
+ var e3 = document.getElementById("1127835crash3");
+ var t1 = e1.childNodes[0];
+ var t3 = e3.childNodes[0];
+
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+
+ var r = document.createRange();
+ r.setStart(t1, 1);
+ r.setEnd(e2, 0);
+ sel.addRange(r); // <div>\n<span id="1127835crash1">1[</span><div id="1127835crash2">}<div>\n</div></div><a href="..." id="1127835crash3">3</a>\n</div>
+
+ r = document.createRange();
+ r.setStart(e2, 1);
+ r.setEnd(t3, 0);
+ sel.addRange(r); // <div>\n<span id="1127835crash1">1</span><div id="1127835crash2"><div>\n</div>{</div><a href="..." id="1127835crash3">]3</a>\n</div>
+ await copySelectionToClipboard(true);
+ testPasteHTML(
+ "contentEditable6",
+ '<span id="1127835crash1"></span><div id="1127835crash2"><div>\n</div></div><a href="http://www.mozilla.org/" id="1127835crash3"><br></a>'
+ ); // Don't strip the empty `<a href="...">` element because of avoiding any dataloss provided by the element
+ }
+
+ // ============ copy/paste test from/to a textarea
+
+ var val = "1\n 2\n 3";
+ textarea.value = val;
+ textarea.select();
+ await SimpleTest.promiseClipboardChange(textarea.value, () => {
+ textarea.editor.copy();
+ });
+ textarea.value = "";
+ textarea.editor.paste(1);
+ is(textarea.value, val);
+ textarea.value = "";
+
+ // ============ NOSCRIPT should not be copied
+
+ await copyChildrenToClipboard("div13");
+ testSelectionToString("__");
+ testClipboardValue("text/plain", "__");
+ testHtmlClipboardValue("text/html", '<div id="div13">__</div>');
+ testPasteText("__");
+
+ // ============ converting cell boundaries to tabs in tables
+
+ await copyToClipboard($("tr1"));
+ testClipboardValue("text/plain", "foo\tbar");
+
+ if (!isXHTML) {
+ // ============ spanning multiple rows
+
+ await copyRangeToClipboard($("tr2"), 0, $("tr3"), 0);
+ testClipboardValue("text/plain", "1\t2\n3\t4\n");
+ testHtmlClipboardValue(
+ "text/html",
+ '<table><tbody><tr id="tr2"><tr id="tr2"><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr><tr id="tr3"></tr></tr></tbody></table>'
+ );
+
+ // ============ spanning multiple rows in multi-range selection
+
+ clear();
+ addRange($("tr2"), 0, $("tr2"), 2);
+ addRange($("tr3"), 0, $("tr3"), 2);
+ await copySelectionToClipboard();
+ testClipboardValue("text/plain", "1\t2\n5\t6");
+ testHtmlClipboardValue(
+ "text/html",
+ '<table><tbody><tr id="tr2"><td>1</td><td>2</td></tr><tr id="tr3"><td>5</td><td>6</td></tr></tbody></table>'
+ );
+ }
+
+ // ============ manipulating Selection in oncopy
+
+ await copyRangeToClipboard(
+ $("div11").childNodes[0],
+ 0,
+ $("div11").childNodes[1],
+ 2
+ );
+ testClipboardValue("text/plain", "Xdiv11");
+ testHtmlClipboardValue("text/html", "<div><p>X<span>div</span>11</p></div>");
+
+ await new Promise(resolve => {
+ setTimeout(resolve, 0);
+ });
+ testSelectionToString("div11");
+
+ await new Promise(resolve => {
+ setTimeout(resolve, 0);
+ });
+ await copyRangeToClipboard(
+ $("div12").childNodes[0],
+ 0,
+ $("div12").childNodes[1],
+ 2
+ );
+
+ testClipboardValue("text/plain", "Xdiv12");
+ testHtmlClipboardValue("text/html", "<div><p>X<span>div</span>12</p></div>");
+ await new Promise(resolve => {
+ setTimeout(resolve, 0);
+ });
+ testSelectionToString("div12");
+
+ await new Promise(resolve => {
+ setTimeout(resolve, 0);
+ });
+
+ if (!isXHTML) {
+ // ============ copy from ruby
+
+ const ruby1 = $("ruby1");
+ const ruby1Container = ruby1.parentNode;
+
+ // Ruby annotation is included when selecting inside ruby.
+ await copyRangeToClipboard(ruby1, 0, ruby1, 6);
+ testClipboardValue("text/plain", "aabb(AABB)");
+
+ // Ruby annotation is ignored when selecting across ruby.
+ await copyRangeToClipboard(ruby1Container, 0, ruby1Container, 3);
+ testClipboardValue("text/plain", "XaabbY");
+
+ // ... unless converter.html2txt.always_include_ruby is set
+ await SpecialPowers.pushPrefEnv({
+ set: [["converter.html2txt.always_include_ruby", true]],
+ });
+ await copyRangeToClipboard(ruby1Container, 0, ruby1Container, 3);
+ testClipboardValue("text/plain", "Xaabb(AABB)Y");
+ await SpecialPowers.popPrefEnv();
+ }
+}
diff --git a/dom/base/test/delayedServerEvents.sjs b/dom/base/test/delayedServerEvents.sjs
new file mode 100644
index 0000000000..cfc1bca508
--- /dev/null
+++ b/dom/base/test/delayedServerEvents.sjs
@@ -0,0 +1,56 @@
+// this will take strings_to_send.length*500 ms = 5 sec
+
+var timer = null;
+var strings_to_send = [
+ "retry:999999999\ndata\r\n\nda",
+ "ta",
+ ":",
+ "de",
+ "layed1\n\n",
+ "",
+ "",
+ "data:delayed2\n\n",
+ "",
+ "",
+];
+var resp = null;
+
+function sendNextString() {
+ if (!strings_to_send.length) {
+ timer.cancel();
+ resp.finish();
+ timer = null;
+ resp = null;
+ return;
+ }
+
+ try {
+ resp.write(strings_to_send.shift());
+ } catch (e) {
+ timer.cancel();
+ timer = null;
+ resp = null;
+ }
+}
+
+function handleRequest(request, response) {
+ var bytes = strings_to_send.reduce((len, s) => len + s.length, 0);
+
+ response.seizePower();
+ response.write("HTTP/1.1 200 OK\r\n");
+ response.write(`Content-Length: ${bytes}\r\n`);
+ response.write("Content-Type: text/event-stream; charset=utf-8\r\n");
+ response.write("Cache-Control: no-cache, must-revalidate\r\n");
+ response.write("\r\n");
+
+ resp = response;
+
+ timer = Components.classes["@mozilla.org/timer;1"].createInstance(
+ Components.interfaces.nsITimer
+ );
+ timer.initWithCallback(
+ sendNextString,
+ 500,
+ Components.interfaces.nsITimer.TYPE_REPEATING_SLACK
+ );
+}
diff --git a/dom/base/test/dummy.html b/dom/base/test/dummy.html
new file mode 100644
index 0000000000..1a87e28408
--- /dev/null
+++ b/dom/base/test/dummy.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Dummy test page</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
+</head>
+<body>
+<p>Dummy test page</p>
+</body>
+</html>
diff --git a/dom/base/test/embed_bug455472.html b/dom/base/test/embed_bug455472.html
new file mode 100644
index 0000000000..d244ea9396
--- /dev/null
+++ b/dom/base/test/embed_bug455472.html
@@ -0,0 +1 @@
+<svg xmlns='http://www.w3.org/2000/svg' onload='parent.ran[2]=true'/>
diff --git a/dom/base/test/empty.html b/dom/base/test/empty.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/base/test/empty.html
diff --git a/dom/base/test/eventsource.resource b/dom/base/test/eventsource.resource
new file mode 100644
index 0000000000..856e3b1aff
--- /dev/null
+++ b/dom/base/test/eventsource.resource
@@ -0,0 +1,22 @@
+:this file must be enconded in utf8
+:and its Content-Type must be equal to text/event-stream
+
+retry:500
+data: 1
+unknow: unknow
+
+event: other_event_name
+retry:500
+data: 1
+unknow: unknow
+
+event: click
+retry:500
+
+event: blur
+retry:500
+
+event:keypress
+retry:500
+
+
diff --git a/dom/base/test/eventsource.resource^headers^ b/dom/base/test/eventsource.resource^headers^
new file mode 100644
index 0000000000..6a63b5341d
--- /dev/null
+++ b/dom/base/test/eventsource.resource^headers^
@@ -0,0 +1,3 @@
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate
+
diff --git a/dom/base/test/eventsource_message.sjs b/dom/base/test/eventsource_message.sjs
new file mode 100644
index 0000000000..d52e2ee432
--- /dev/null
+++ b/dom/base/test/eventsource_message.sjs
@@ -0,0 +1,12 @@
+function handleRequest(request, response) {
+ var match = request.queryString.match(/^status=(.*)$/);
+ var status = match ? +match[1] : 200;
+
+ if (status != 200) {
+ response.setStatusLine(request.httpVersion, status, "Err");
+ }
+ response.setHeader("Content-Type", "text/event-stream");
+ response.setHeader("Cache-Control", "no-cache");
+ response.write("data: msg 1\n");
+ response.write("id: 1\n\n");
+}
diff --git a/dom/base/test/eventsource_reconnect.sjs b/dom/base/test/eventsource_reconnect.sjs
new file mode 100644
index 0000000000..6627fefa9f
--- /dev/null
+++ b/dom/base/test/eventsource_reconnect.sjs
@@ -0,0 +1,18 @@
+function handleRequest(request, response) {
+ var name = "eventsource_reconnecting_" + request.queryString;
+ var reconnecting = getState(name);
+ var body = "";
+ if (!reconnecting) {
+ body = "retry: 2\n";
+ setState(name, "0");
+ } else if (reconnecting === "0") {
+ setState(name, "");
+ response.setStatusLine(request.httpVersion, 204, "No Content");
+ }
+
+ response.setHeader("Content-Type", "text/event-stream");
+ response.setHeader("Cache-Control", "no-cache");
+
+ body += "data: 1\n\n";
+ response.write(body);
+}
diff --git a/dom/base/test/eventsource_redirect.resource b/dom/base/test/eventsource_redirect.resource
new file mode 100644
index 0000000000..d073527bfb
--- /dev/null
+++ b/dom/base/test/eventsource_redirect.resource
@@ -0,0 +1,2 @@
+redirected
+
diff --git a/dom/base/test/eventsource_redirect.resource^headers^ b/dom/base/test/eventsource_redirect.resource^headers^
new file mode 100644
index 0000000000..eb79e2f814
--- /dev/null
+++ b/dom/base/test/eventsource_redirect.resource^headers^
@@ -0,0 +1,3 @@
+HTTP 301 Moved Permanently
+Location: eventsource_redirect_to.resource
+
diff --git a/dom/base/test/eventsource_redirect_to.resource b/dom/base/test/eventsource_redirect_to.resource
new file mode 100644
index 0000000000..1eb4081ac1
--- /dev/null
+++ b/dom/base/test/eventsource_redirect_to.resource
@@ -0,0 +1,4 @@
+retry:500
+data: 1
+
+
diff --git a/dom/base/test/eventsource_redirect_to.resource^headers^ b/dom/base/test/eventsource_redirect_to.resource^headers^
new file mode 100644
index 0000000000..6a63b5341d
--- /dev/null
+++ b/dom/base/test/eventsource_redirect_to.resource^headers^
@@ -0,0 +1,3 @@
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate
+
diff --git a/dom/base/test/eventsource_worker.js b/dom/base/test/eventsource_worker.js
new file mode 100644
index 0000000000..863d52eec1
--- /dev/null
+++ b/dom/base/test/eventsource_worker.js
@@ -0,0 +1,6 @@
+const es = new EventSource(
+ "http://mochi.test:8888/tests/dom/base/test/eventsource_message.sjs"
+);
+es.onmessage = function () {
+ es.close();
+};
diff --git a/dom/base/test/fake_plugin.tst b/dom/base/test/fake_plugin.tst
new file mode 100644
index 0000000000..b3d41aed8d
--- /dev/null
+++ b/dom/base/test/fake_plugin.tst
@@ -0,0 +1 @@
+This is used in test_object.html to test loading by extension (.tst -> application/x-test).
diff --git a/dom/base/test/file1_setting_opener.html b/dom/base/test/file1_setting_opener.html
new file mode 100644
index 0000000000..6bc319bc9e
--- /dev/null
+++ b/dom/base/test/file1_setting_opener.html
@@ -0,0 +1 @@
+<script>opener.setTimeout(opener.basicOpenerTest, 0, this)</script>
diff --git a/dom/base/test/file2_setting_opener.html b/dom/base/test/file2_setting_opener.html
new file mode 100644
index 0000000000..b0f383ad23
--- /dev/null
+++ b/dom/base/test/file2_setting_opener.html
@@ -0,0 +1 @@
+<script>opener.setTimeout(opener.continueOpenerTest, 0, this);</script>
diff --git a/dom/base/test/file3_setting_opener.html b/dom/base/test/file3_setting_opener.html
new file mode 100644
index 0000000000..a40a0706f9
--- /dev/null
+++ b/dom/base/test/file3_setting_opener.html
@@ -0,0 +1 @@
+<script>opener.setTimeout(opener.continueOpenerTest2, 0, this);</script>
diff --git a/dom/base/test/file4_setting_opener.html b/dom/base/test/file4_setting_opener.html
new file mode 100644
index 0000000000..50b5b54a0e
--- /dev/null
+++ b/dom/base/test/file4_setting_opener.html
@@ -0,0 +1 @@
+Loaded
diff --git a/dom/base/test/file_audioLoop.html b/dom/base/test/file_audioLoop.html
new file mode 100644
index 0000000000..d680c9a58f
--- /dev/null
+++ b/dom/base/test/file_audioLoop.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<audio src="audio.ogg" autoplay="true" loop>
diff --git a/dom/base/test/file_audioLoopInIframe.html b/dom/base/test/file_audioLoopInIframe.html
new file mode 100644
index 0000000000..1131d140b3
--- /dev/null
+++ b/dom/base/test/file_audioLoopInIframe.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="file_audioLoop.html"></iframe>
diff --git a/dom/base/test/file_blocking_image.html b/dom/base/test/file_blocking_image.html
new file mode 100644
index 0000000000..8b66cb0c5b
--- /dev/null
+++ b/dom/base/test/file_blocking_image.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html xml:lang="en-US" lang="en-US">
+ <head>
+ <meta charset="utf8" http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
+ <title>Image Blocking test </title>
+ </head>
+ <body>
+ </body>
+</html>
+
diff --git a/dom/base/test/file_browser_refresh_content.html b/dom/base/test/file_browser_refresh_content.html
new file mode 100644
index 0000000000..aa338efd3f
--- /dev/null
+++ b/dom/base/test/file_browser_refresh_content.html
@@ -0,0 +1,41 @@
+<html>
+ <body>
+ <img src="file_browser_refresh_image.sjs">
+ <iframe src="file_browser_refresh_iframe.sjs"></iframe>
+ <div id="result"></div>
+
+ <canvas id="canvas" width="100" height="100"> </canvas>
+ <script>
+ const image = document.querySelector("img");
+ const iframe = document.querySelector("iframe");
+ const result = document.getElementById("result");
+
+ iframe.addEventListener("load", function() {
+ result.setAttribute(
+ "iframeContent",
+ iframe.contentDocument.body.textContent
+ );
+ });
+
+ // Ensure images are loaded
+ image.addEventListener("load", function() {
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(image, 0, 0);
+
+ result.setAttribute("imageDataURL", canvas.toDataURL());
+ });
+
+ // Ensure expired resources are still loaded
+ fetch('./file_browser_refresh_expired_resource.sjs').then((response) => {
+ let cacheControl = response.headers.get('Cache-Control');
+ result.setAttribute("expiredResourceCacheControl", cacheControl);
+ });
+
+ // Ensure non cacheable resources are still loaded
+ fetch('./file_browser_refresh_non_cacheable.sjs').then(() => {
+ result.setAttribute("nonCacheableResourceCompleted", true);
+ });
+ </script>
+ </body>
+</html>
diff --git a/dom/base/test/file_browser_refresh_expired_resource.sjs b/dom/base/test/file_browser_refresh_expired_resource.sjs
new file mode 100644
index 0000000000..ab5cdcf78d
--- /dev/null
+++ b/dom/base/test/file_browser_refresh_expired_resource.sjs
@@ -0,0 +1,13 @@
+"use strict";
+
+function handleRequest(request, response) {
+ if (getState("expired_resource") == "") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Cache-Control", "max-age=1001");
+ setState("expired_resource", "ok");
+ } else {
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Cache-Control", "max-age=1003");
+ setState("expired_resource", "");
+ }
+}
diff --git a/dom/base/test/file_browser_refresh_iframe.sjs b/dom/base/test/file_browser_refresh_iframe.sjs
new file mode 100644
index 0000000000..0941a1160e
--- /dev/null
+++ b/dom/base/test/file_browser_refresh_iframe.sjs
@@ -0,0 +1,13 @@
+"use strict";
+
+function handleRequest(request, response) {
+ if (getState("iframe_resource") == "") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("first load");
+ setState("iframe_resource", "ok");
+ } else {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("second load");
+ setState("iframe_resource", "");
+ }
+}
diff --git a/dom/base/test/file_browser_refresh_image.sjs b/dom/base/test/file_browser_refresh_image.sjs
new file mode 100644
index 0000000000..17f11e87e9
--- /dev/null
+++ b/dom/base/test/file_browser_refresh_image.sjs
@@ -0,0 +1,38 @@
+"use strict";
+
+function handleRequest(request, response) {
+ const file = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+
+ file.append("tests");
+ file.append("image");
+ file.append("test");
+ file.append("mochitest");
+
+ const redirectstate = "image_resource";
+ if (getState(redirectstate) == "") {
+ file.append("green.png");
+ setState(redirectstate, "green");
+ } else {
+ file.append("red.png");
+ setState(redirectstate, "");
+ }
+
+ response.setHeader("Cache-Control", "max-age=3600", false);
+
+ const fileStream = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+
+ fileStream.init(file, 1, 0, false);
+ const binaryStream = Components.classes[
+ "@mozilla.org/binaryinputstream;1"
+ ].createInstance(Components.interfaces.nsIBinaryInputStream);
+ binaryStream.setInputStream(fileStream);
+
+ response.bodyOutputStream.writeFrom(binaryStream, binaryStream.available());
+
+ binaryStream.close();
+ fileStream.close();
+}
diff --git a/dom/base/test/file_browser_refresh_non_cacheable.sjs b/dom/base/test/file_browser_refresh_non_cacheable.sjs
new file mode 100644
index 0000000000..9b5a39abed
--- /dev/null
+++ b/dom/base/test/file_browser_refresh_non_cacheable.sjs
@@ -0,0 +1,6 @@
+"use strict";
+
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Cache-Control", "no-store");
+}
diff --git a/dom/base/test/file_bug1008126_worker.js b/dom/base/test/file_bug1008126_worker.js
new file mode 100644
index 0000000000..aaba278de5
--- /dev/null
+++ b/dom/base/test/file_bug1008126_worker.js
@@ -0,0 +1,151 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var gEntry1 = "data_1.txt";
+var gEntry2 = "data_2.txt";
+var gEntry3 = "data_big.txt";
+var gPaddingChar = ".";
+var gPaddingSize = 10000;
+var gPadding = "";
+for (var i = 0; i < gPaddingSize; i++) {
+ gPadding += gPaddingChar;
+}
+var gData1 = "TEST_DATA_1:ABCDEFGHIJKLMNOPQRSTUVWXYZ" + gPadding;
+var gData2 = "TEST_DATA_2:1234567890" + gPadding;
+
+function ok(a, msg) {
+ postMessage({ type: "status", status: !!a, msg });
+}
+
+function is(a, b, msg) {
+ postMessage({ type: "status", status: a === b, msg });
+}
+
+function checkData(xhr, data, mapped, cb) {
+ var ct = xhr.getResponseHeader("Content-Type");
+ if (mapped) {
+ ok(ct.includes("mem-mapped"), "Data is memory-mapped");
+ } else {
+ ok(!ct.includes("mem-mapped"), "Data is not memory-mapped");
+ }
+ ok(xhr.response, "Data is non-null");
+ var str = String.fromCharCode.apply(null, new Uint8Array(xhr.response));
+ ok(str == data, "Data is correct");
+ cb();
+}
+
+self.onmessage = function onmessage(event) {
+ var jar = event.data;
+
+ function makeJarURL(entry) {
+ return "jar:" + jar + "!/" + entry;
+ }
+
+ var xhr = new XMLHttpRequest({ mozAnon: true, mozSystem: true });
+
+ function reset_event_hander() {
+ xhr.onerror = function (e) {
+ ok(false, "Error: " + e.error + "\n");
+ };
+ xhr.onprogress = null;
+ xhr.onreadystatechange = null;
+ xhr.onload = null;
+ xhr.onloadend = null;
+ }
+
+ var readystatechangeCount = 0;
+ var loadCount = 0;
+ var loadendCount = 0;
+
+ function checkEventCount(cb) {
+ ok(
+ readystatechangeCount == 1 && loadCount == 1 && loadendCount == 1,
+ "Saw all expected events"
+ );
+ cb();
+ }
+
+ function test_multiple_events() {
+ ok(true, "Test multiple events");
+ xhr.abort();
+
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState == xhr.DONE) {
+ readystatechangeCount++;
+ checkData(xhr, gData2, false, function () {});
+ }
+ };
+ xhr.onload = function () {
+ loadCount++;
+ checkData(xhr, gData2, false, function () {});
+ };
+ xhr.onloadend = function () {
+ loadendCount++;
+ checkData(xhr, gData2, false, function () {});
+ };
+ xhr.open("GET", makeJarURL(gEntry2), false);
+ xhr.responseType = "arraybuffer";
+ xhr.send();
+ checkEventCount(runTests);
+ }
+
+ function test_sync_xhr_data1() {
+ ok(true, "Test sync XHR with data1");
+ xhr.open("GET", makeJarURL(gEntry1), false);
+ xhr.responseType = "arraybuffer";
+ xhr.send();
+ checkData(xhr, gData1, true, runTests);
+ }
+
+ function test_sync_xhr_data2() {
+ ok(true, "Test sync XHR with data2");
+ xhr.open("GET", makeJarURL(gEntry2), false);
+ xhr.responseType = "arraybuffer";
+ xhr.send();
+ checkData(xhr, gData2, false, runTests);
+ }
+
+ function test_async_xhr_data1() {
+ ok(true, "Test async XHR with data1");
+ xhr.onload = function () {
+ checkData(xhr, gData1, true, runTests);
+ };
+ xhr.open("GET", makeJarURL(gEntry1), true);
+ xhr.responseType = "arraybuffer";
+ xhr.send();
+ }
+
+ function test_async_xhr_data2() {
+ ok(true, "Test async XHR with data2");
+ xhr.onload = function () {
+ checkData(xhr, gData2, false, runTests);
+ };
+ xhr.open("GET", makeJarURL(gEntry2), true);
+ xhr.responseType = "arraybuffer";
+ xhr.send();
+ }
+
+ var tests = [
+ test_multiple_events,
+ test_sync_xhr_data1,
+ test_sync_xhr_data2,
+ test_async_xhr_data1,
+ test_async_xhr_data2,
+ ];
+
+ function runTests() {
+ if (!tests.length) {
+ postMessage({ type: "finish" });
+ return;
+ }
+
+ reset_event_hander();
+
+ var test = tests.shift();
+ test();
+ }
+
+ runTests();
+};
diff --git a/dom/base/test/file_bug1011748_OK.sjs b/dom/base/test/file_bug1011748_OK.sjs
new file mode 100644
index 0000000000..71a0f5c3e8
--- /dev/null
+++ b/dom/base/test/file_bug1011748_OK.sjs
@@ -0,0 +1,4 @@
+// Function to indicate HTTP 200 OK after redirect from file_bug1011748_redirect.sjs
+function handleRequest(request, response) {
+ response.setStatusLine(null, 200, "OK");
+}
diff --git a/dom/base/test/file_bug1011748_redirect.sjs b/dom/base/test/file_bug1011748_redirect.sjs
new file mode 100644
index 0000000000..3dec893675
--- /dev/null
+++ b/dom/base/test/file_bug1011748_redirect.sjs
@@ -0,0 +1,5 @@
+// SJS handler to redirect the XMLHttpRequest object to file_bug1011748_OK.sjs
+function handleRequest(request, response) {
+ response.setStatusLine(null, 302, "Moved Temporarily");
+ response.setHeader("Location", "file_bug1011748_OK.sjs", false);
+}
diff --git a/dom/base/test/file_bug1091883_frame.html b/dom/base/test/file_bug1091883_frame.html
new file mode 100644
index 0000000000..a245175ae3
--- /dev/null
+++ b/dom/base/test/file_bug1091883_frame.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<body>
+<h2>Frame I am.</h2>
+<script>
+var subframeOrigin = location.hash.substr(1); // e.g., "http://example.com"
+var subframe = document.createElement("iframe");
+subframe.src = subframeOrigin +
+ "/tests/dom/base/test/file_bug1091883_subframe.html";
+document.body.appendChild(subframe);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1091883_subframe.html b/dom/base/test/file_bug1091883_subframe.html
new file mode 100644
index 0000000000..f282e1eeb9
--- /dev/null
+++ b/dom/base/test/file_bug1091883_subframe.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<h3>Subframe I am.</h3>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1091883_target.html b/dom/base/test/file_bug1091883_target.html
new file mode 100644
index 0000000000..2095595fbc
--- /dev/null
+++ b/dom/base/test/file_bug1091883_target.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<h3>Target I am.</h3>
+<script>
+var testRun = location.hash.substr(1);
+parent.parent.postMessage(document.referrer + " " + testRun,
+ "http://mochi.test:8888");
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1100912.html b/dom/base/test/file_bug1100912.html
new file mode 100644
index 0000000000..8fac15fae4
--- /dev/null
+++ b/dom/base/test/file_bug1100912.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1100912
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1100912</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ td {
+ border-right: 1px solid black;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1100912">Mozilla Bug 1100912</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+ <!-- The table is here just to make the web page easier to read -->
+ <table>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ </tr>
+
+ <tr><td>1.</td><td>
+ <div id="host1" dir="rtl"><span> 3 4 </span></div>
+ </td><td></td><td>rtl on host</td></tr>
+
+ <tr><td>2.</td><td>
+ <div id="host2" dir="rtl"><span> 3 4 </span></div>
+ </td><td></td><td>rtl on host, ltr slot's parent</td></tr>
+
+ <tr><td>3.</td><td>
+ <div id="host3" dir="rtl"><span> 3 4 </span></div>
+ </td><td></td><td>rtl on host, ltr on slot</td></tr>
+
+ <tr><td>4.</td><td>
+ <div id="host4" dir="auto"><span> 1 2 </span></div>
+ </td><td></td><td>auto host, rtl in shadow</td></tr>
+
+ <tr><td>5.</td><td>
+ <div id="host5" dir="auto"><span> &#1571;&#1582;&#1576;&#1575;&#1585; </span></div>
+ </td><td></td><td>auto host, rtl in host (in assigned node)</td></tr>
+
+ <tr><td>6.</td><td>
+ <div id="host6" dir="auto"><span> &#1571;&#1582;&#1576;&#1575;&#1585; </span></div>
+ </td><td></td><td>auto host, rtl in host, no assigned node</td></tr>
+
+ <tr><td>7.</td><td>
+ <div id="host7" dir="auto"><span> &#1571;&#1582;&#1576;&#1575;&#1585; </span></div>
+ </td><td></td><td>auto host, rtl in host, explicit ltr in shadow</td></tr>
+
+ <tr><td>8.</td><td>
+ <div id="host8" dir="auto"><span slot="second">&lrm;1 2 </span><span slot="first"> &#1571;&#1582;&#1576;&#1575;&#1585; </span></div>
+ </td><td></td><td>auto host, ltr in host, rtl in host, reverse order in slots</td></tr>
+
+ <tr><td>9.</td><td>
+ <div id="host9" dir="auto">&#1571;&#1582;&#1576;&#1575;&#1585;</div>
+ </td><td></td><td>auto host, rtl in host (in assigned text node)</td></tr>
+
+ <tr><td>10.</td><td>
+ <div id="host10" dir="auto"> 1 2</div>
+ </td><td></td><td>auto host, 1 2 in host (in assigned text node)</td></tr>
+
+</table>
+<script>
+
+function ltrExpected(element) {
+ opener.is(element.parentNode.querySelector(":dir(ltr)"), element,
+ "Should have got an ltr element.");
+}
+
+function rtlExpected(element) {
+ opener.is(element.parentNode.querySelector(":dir(rtl)"), element,
+ "Should have got an rtl element.");
+}
+
+const shadowRoot1 = host1.attachShadow({mode: 'closed'});
+shadowRoot1.innerHTML = '<div> 1 2 <span><slot></slot></span></div>';
+rtlExpected(host1);
+rtlExpected(host1.firstChild);
+rtlExpected(shadowRoot1.firstChild.lastChild); // span in the Shadow DOM
+
+const shadowRoot2 = host2.attachShadow({mode: 'closed'});
+shadowRoot2.innerHTML = '<div> 1 2 <span dir="ltr"><slot></slot></span></div>';
+rtlExpected(host2);
+ltrExpected(host2.firstChild);
+
+// This is weird case, and we have similar behavior as Blink. dir= on <slot>
+// doesn't affect to UI since slot has display: contents by default.
+const shadowRoot3 = host3.attachShadow({mode: 'closed'});
+shadowRoot3.innerHTML = '<div> 1 2 <span><slot dir="ltr"></slot></span></div>';
+rtlExpected(host3);
+
+const shadowRoot4 = host4.attachShadow({mode: 'closed'});
+shadowRoot4.innerHTML = '<div> &#1571;&#1582;&#1576;&#1575;&#1585; <span><slot></slot></span></div>';
+rtlExpected(host4);
+rtlExpected(host4.firstChild);
+rtlExpected(shadowRoot4.firstChild.lastChild);
+
+const shadowRoot5 = host5.attachShadow({mode: 'closed'});
+shadowRoot5.innerHTML = '<div> 1 2 <span><slot></slot></span></div>';
+rtlExpected(host5);
+rtlExpected(host5.firstChild);
+rtlExpected(shadowRoot5.firstChild.lastChild);
+
+// This case is different to Blink since it doesn't deal with nodes which aren't
+// in the flattened tree, so it doesn't detect rtl in child nodes, which
+// aren't assigned to any slot.
+const shadowRoot6 = host6.attachShadow({mode: 'closed'});
+shadowRoot6.innerHTML = '<div> 1 2 <span></span></div>';
+rtlExpected(host6);
+rtlExpected(host6.firstChild);
+rtlExpected(shadowRoot6.firstChild.lastChild);
+
+const shadowRoot7 = host7.attachShadow({mode: 'closed'});
+shadowRoot7.innerHTML = '<div> &lrm;1 2 <span><slot></slot></span></div>';
+ltrExpected(host7);
+ltrExpected(host7.firstChild);
+ltrExpected(shadowRoot7.firstChild.lastChild);
+
+const shadowRoot8 = host8.attachShadow({mode: 'closed'});
+shadowRoot8.innerHTML = '<div><slot name="first"></slot><slot name="second"></slot></div>';
+rtlExpected(host8);
+rtlExpected(host8.firstChild);
+rtlExpected(shadowRoot8.firstChild.firstChild);
+
+const shadowRoot9 = host9.attachShadow({mode: 'closed'});
+shadowRoot9.innerHTML = '<div> 1 2 <span><slot></slot></span></div>';
+rtlExpected(host9);
+rtlExpected(shadowRoot9.firstChild.lastChild);
+
+const shadowRoot10 = host10.attachShadow({mode: 'closed'});
+shadowRoot10.innerHTML = '<div> &#1571;&#1582;&#1576;&#1575;&#1585; <span><slot></slot></span></div>';
+rtlExpected(host10);
+rtlExpected(shadowRoot10.firstChild.lastChild);
+
+opener.didRunTests();
+window.close();
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_bug1198095.js b/dom/base/test/file_bug1198095.js
new file mode 100644
index 0000000000..2b8c018de7
--- /dev/null
+++ b/dom/base/test/file_bug1198095.js
@@ -0,0 +1,38 @@
+/* eslint-env mozilla/chrome-script */
+
+Cu.importGlobalProperties(["File"]);
+
+function createFileWithData(message) {
+ var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(
+ Ci.nsIProperties
+ );
+ var testFile = dirSvc.get("ProfD", Ci.nsIFile);
+ testFile.append("fileAPItestfileBug1198095");
+
+ var outStream = Cc[
+ "@mozilla.org/network/file-output-stream;1"
+ ].createInstance(Ci.nsIFileOutputStream);
+ outStream.init(
+ testFile,
+ 0x02 | 0x08 | 0x20, // write, create, truncate
+ 0o666,
+ 0
+ );
+
+ outStream.write(message, message.length);
+ outStream.close();
+
+ return File.createFromNsIFile(testFile);
+}
+
+addMessageListener("file.open", function (message) {
+ createFileWithData(message).then(function (file) {
+ sendAsyncMessage("file.opened", file);
+ });
+});
+
+addMessageListener("file.modify", function (message) {
+ createFileWithData(message).then(function (file) {
+ sendAsyncMessage("file.modified", file);
+ });
+});
diff --git a/dom/base/test/file_bug1250148.sjs b/dom/base/test/file_bug1250148.sjs
new file mode 100644
index 0000000000..5f8037a08a
--- /dev/null
+++ b/dom/base/test/file_bug1250148.sjs
@@ -0,0 +1,73 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+function utf8decode(s) {
+ return decodeURIComponent(escape(s));
+}
+
+function utf8encode(s) {
+ return unescape(encodeURIComponent(s));
+}
+
+function handleRequest(request, response) {
+ var bodyStream = new BinaryInputStream(request.bodyInputStream);
+
+ var requestBody = "";
+ while ((bodyAvail = bodyStream.available()) > 0) {
+ requestBody += bodyStream.readBytes(bodyAvail);
+ }
+
+ var result = [];
+
+ if (request.method == "POST") {
+ var contentTypeParams = {};
+ request
+ .getHeader("Content-Type")
+ .split(/\s*\;\s*/)
+ .forEach(function (str) {
+ if (str.indexOf("=") >= 0) {
+ let [name, value] = str.split("=");
+ contentTypeParams[name] = value;
+ } else {
+ contentTypeParams[""] = str;
+ }
+ });
+
+ if (
+ contentTypeParams[""] == "multipart/form-data" &&
+ request.queryString == ""
+ ) {
+ requestBody
+ .split("--" + contentTypeParams.boundary)
+ .slice(1, -1)
+ .forEach(function (s) {
+ let headers = {};
+ let headerEnd = s.indexOf("\r\n\r\n");
+ s.substr(2, headerEnd - 2)
+ .split("\r\n")
+ .forEach(function (str) {
+ // We're assuming UTF8 for now
+ let [name, value] = str.split(": ");
+ headers[name] = utf8decode(value);
+ });
+
+ let body = s.substring(headerEnd + 4, s.length - 2);
+ if (
+ !headers["Content-Type"] ||
+ headers["Content-Type"] == "text/plain"
+ ) {
+ // We're assuming UTF8 for now
+ body = utf8decode(body);
+ }
+ result.push({ headers, body });
+ });
+ }
+ }
+
+ response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
+ response.write(utf8encode(JSON.stringify(result)));
+}
diff --git a/dom/base/test/file_bug1268962.sjs b/dom/base/test/file_bug1268962.sjs
new file mode 100644
index 0000000000..1aa06fadaa
--- /dev/null
+++ b/dom/base/test/file_bug1268962.sjs
@@ -0,0 +1,92 @@
+// Test server for bug 1268962
+"use strict";
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+const HTTPStatus = new Map([
+ [100, "Continue"],
+ [101, "Switching Protocol"],
+ [200, "OK"],
+ [201, "Created"],
+ [202, "Accepted"],
+ [203, "Non-Authoritative Information"],
+ [204, "No Content"],
+ [205, "Reset Content"],
+ [206, "Partial Content"],
+ [300, "Multiple Choice"],
+ [301, "Moved Permanently"],
+ [302, "Found"],
+ [303, "See Other"],
+ [304, "Not Modified"],
+ [305, "Use Proxy"],
+ [306, "unused"],
+ [307, "Temporary Redirect"],
+ [308, "Permanent Redirect"],
+ [400, "Bad Request"],
+ [401, "Unauthorized"],
+ [402, "Payment Required"],
+ [403, "Forbidden"],
+ [404, "Not Found"],
+ [405, "Method Not Allowed"],
+ [406, "Not Acceptable"],
+ [407, "Proxy Authentication Required"],
+ [408, "Request Timeout"],
+ [409, "Conflict"],
+ [410, "Gone"],
+ [411, "Length Required"],
+ [412, "Precondition Failed"],
+ [413, "Request Entity Too Large"],
+ [414, "Request-URI Too Long"],
+ [415, "Unsupported Media Type"],
+ [416, "Requested Range Not Satisfiable"],
+ [417, "Expectation Failed"],
+ [500, "Internal Server Error"],
+ [501, "Not Implemented"],
+ [502, "Bad Gateway"],
+ [503, "Service Unavailable"],
+ [504, "Gateway Timeout"],
+ [505, "HTTP Version Not Supported"],
+]);
+
+const SAME_ORIGIN =
+ "http://mochi.test:8888/tests/dom/base/test/file_bug1268962.sjs";
+const CROSS_ORIGIN =
+ "http://example.com/tests/dom/base/test/file_bug1268962.sjs";
+
+function handleRequest(request, response) {
+ const queryMap = new URLSearchParams(request.queryString);
+
+ // Check redirection before everything else.
+ if (queryMap.has("redirect")) {
+ let redirect = queryMap.get("redirect");
+ let location;
+ if (redirect == "sameorigin") {
+ location = SAME_ORIGIN;
+ } else if (redirect == "crossorigin") {
+ location = CROSS_ORIGIN;
+ }
+
+ if (location) {
+ // Use HTTP 302 redirection.
+ response.setStatusLine("1.1", 302, HTTPStatus.get(302));
+
+ // Forward query strings except the redirect option.
+ queryMap.delete("redirect");
+ response.setHeader("Location", location + "?" + queryMap.toString());
+
+ return;
+ }
+ }
+
+ if (queryMap.has("statusCode")) {
+ let statusCode = parseInt(queryMap.get("statusCode"));
+ let statusText = HTTPStatus.get(statusCode);
+ response.setStatusLine("1.1", statusCode, statusText);
+ }
+ if (queryMap.has("cacheControl")) {
+ let cacheControl = queryMap.get("cacheControl");
+ response.setHeader("Cache-Control", cacheControl);
+ }
+ if (queryMap.has("allowOrigin")) {
+ let allowOrigin = queryMap.get("allowOrigin");
+ response.setHeader("Access-Control-Allow-Origin", allowOrigin);
+ }
+}
diff --git a/dom/base/test/file_bug1274806.html b/dom/base/test/file_bug1274806.html
new file mode 100644
index 0000000000..62bef3044b
--- /dev/null
+++ b/dom/base/test/file_bug1274806.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <title></title>
+ <script>
+ window.onload = function() {
+ setTimeout(function() {
+ var rng = document.createRange();
+ rng.setStart(document.getElementsByTagName("p").item(0).firstChild, 100);
+ rng.setEndAfter(document.getElementsByTagName("p").item(0));
+ try {
+ rng.extractContents();
+ opener.ok(true, "extractContents should not throw when document in iframe is being modified.");
+ } catch(ex) {
+ opener.ok(false, "extractContents shouldn't have thrown: " + ex);
+ }
+
+ opener.setTimeout("SimpleTest.finish();", 0);
+ window.close();
+
+ }, 0);
+ };
+ </script>
+</head>
+<body>
+<p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur elit nisi, convallis sed scelerisque sit amet, vestibulum eu odio. Pellentesque et quam et nibh sollicitudin rutrum. Fusce tristique hendrerit ligula, et euismod sapien facilisis quis. Donec tincidunt turpis tortor, in pharetra tellus euismod ac. Vestibulum consectetur nulla lacinia, consectetur mauris ac, tempus libero. Nam non dui id enim dapibus porta id sed lectus. Praesent at suscipit neque. Vestibulum tellus lorem, placerat et volutpat sed, elementum eget lacus. Sed interdum nisi et imperdiet varius. Sed non magna odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus velit risus, accumsan nec efficitur nec, semper sed arcu. Praesent consectetur lectus justo, fringilla imperdiet neque lobortis id. Donec efficitur pulvinar finibus.
+ <iframe src="data:text/html,<script>window.onunload = function() {document.removeChild(document.documentElement); }</script>" width="10" height="10"></iframe>
+</p>
+<p>test</p>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1303838.html b/dom/base/test/file_bug1303838.html
new file mode 100644
index 0000000000..d11444a449
--- /dev/null
+++ b/dom/base/test/file_bug1303838.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Tests for tab switching on link clicks.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tests for tab switching on link clicks.</title>
+ <style>
+ a {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ overflow: hidden;
+ background-color: currentColor;
+ }
+ </style>
+</head>
+<body>
+ <a id="link-1" target="testTab" href="file_bug1303838_target_foo.html">Link 1</a>,
+ <a id="link-2" target="testTab" href="file_bug1303838_target_bar.html">Link 2</a>,
+ <a id="link-3" target="testTab" href="file_bug1303838_target_baz.html">Link 3</a>,
+ <a id="link-4" href="#" onclick="testTab = window.open('file_bug1303838_target_foo.html', 'testTab'); return false;">Link 4</a>,
+ <a id="link-5" href="#" onclick="testTab.location.href += '?1'; return false;">Link 5</a>,
+ <a id="link-6" href="#" onclick="testTab.location.href += '#1'; return false;">Link 6</a>,
+ <a id="link-7" target="testTab" href="file_bug1303838_target.html">Link 7</a>,
+ <a id="anchor-link-1" target="testTab" href="file_bug1303838_target.html#foo">Anchor Link 1</a>,
+ <a id="anchor-link-2" target="testTab" href="file_bug1303838_target.html#bar">Anchor Link 2</a>,
+ <a id="anchor-link-3" target="testTab" href="file_bug1303838_target.html#baz">Anchor Link 3</a>,
+ <a id="frame-link-1" target="testFrame" href="file_bug1303838_target_ifoo.html">Frame Link 1</a>,
+ <a id="frame-link-2" target="testFrame" href="file_bug1303838_target_ibar.html">Frame Link 2</a>,
+ <a id="frame-link-3" target="testFrame" href="file_bug1303838_target_ibaz.html">Frame Link 3</a>,
+</body>
+</html>
diff --git a/dom/base/test/file_bug1303838_target.html b/dom/base/test/file_bug1303838_target.html
new file mode 100644
index 0000000000..b1c8871f6b
--- /dev/null
+++ b/dom/base/test/file_bug1303838_target.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Tests for tab switching on link clicks.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tests for tab switching on link clicks.</title>
+</head>
+<body onload="setTimeout(loadTestFrame, 0);">
+ <div id="foo">Foo</div>
+ <div id="bar">Bar</div>
+ <div id="baz">Baz</div>
+ <iframe name="testFrame"></iframe>
+ <script>
+ function loadTestFrame() {
+ window.open("data:text/html;charset=utf-8,testFrame", "testFrame");
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1303838_target_bar.html b/dom/base/test/file_bug1303838_target_bar.html
new file mode 100644
index 0000000000..2f1aa2bdef
--- /dev/null
+++ b/dom/base/test/file_bug1303838_target_bar.html
@@ -0,0 +1 @@
+<html><body>bar</body></html>
diff --git a/dom/base/test/file_bug1303838_target_baz.html b/dom/base/test/file_bug1303838_target_baz.html
new file mode 100644
index 0000000000..7b4e4c0ef3
--- /dev/null
+++ b/dom/base/test/file_bug1303838_target_baz.html
@@ -0,0 +1 @@
+<html><body>baz</body></html>
diff --git a/dom/base/test/file_bug1303838_target_foo.html b/dom/base/test/file_bug1303838_target_foo.html
new file mode 100644
index 0000000000..f0ab6775c0
--- /dev/null
+++ b/dom/base/test/file_bug1303838_target_foo.html
@@ -0,0 +1 @@
+<html><body>foo</body></html>
diff --git a/dom/base/test/file_bug1303838_target_ibar.html b/dom/base/test/file_bug1303838_target_ibar.html
new file mode 100644
index 0000000000..4832b38ce6
--- /dev/null
+++ b/dom/base/test/file_bug1303838_target_ibar.html
@@ -0,0 +1 @@
+<html><body>ibar</body></html>
diff --git a/dom/base/test/file_bug1303838_target_ibaz.html b/dom/base/test/file_bug1303838_target_ibaz.html
new file mode 100644
index 0000000000..243b786a5b
--- /dev/null
+++ b/dom/base/test/file_bug1303838_target_ibaz.html
@@ -0,0 +1 @@
+<html><body>ibaz</body></html>
diff --git a/dom/base/test/file_bug1303838_target_ifoo.html b/dom/base/test/file_bug1303838_target_ifoo.html
new file mode 100644
index 0000000000..b6c3a90e2e
--- /dev/null
+++ b/dom/base/test/file_bug1303838_target_ifoo.html
@@ -0,0 +1 @@
+<html><body>ifoo</body></html>
diff --git a/dom/base/test/file_bug1303838_with_iframe.html b/dom/base/test/file_bug1303838_with_iframe.html
new file mode 100644
index 0000000000..d949ad7383
--- /dev/null
+++ b/dom/base/test/file_bug1303838_with_iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Tests for tab switching on link clicks.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tests for tab switching on link clicks.</title>
+</head>
+<body>
+ <iframe id="frame" src="file_bug1303838.html"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1554070_1.html b/dom/base/test/file_bug1554070_1.html
new file mode 100644
index 0000000000..0294485293
--- /dev/null
+++ b/dom/base/test/file_bug1554070_1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1554070
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1554070</title>
+</head>
+<body>
+ <iframe name="foo"></iframe>
+ <a href="file_bug1554070_2.html">file_bug1554070_2.html</a>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1554070_2.html b/dom/base/test/file_bug1554070_2.html
new file mode 100644
index 0000000000..9287f535d4
--- /dev/null
+++ b/dom/base/test/file_bug1554070_2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1554070
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1554070</title>
+</head>
+<body>
+ <a href="https://example.org" target="foo">example.org</a>
+</body>
+</html>
diff --git a/dom/base/test/file_bug1639328.html b/dom/base/test/file_bug1639328.html
new file mode 100644
index 0000000000..97c96cf96c
--- /dev/null
+++ b/dom/base/test/file_bug1639328.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<script>
+onmessage = function(e) {
+ parent.postMessage({
+ throttledFrameRequests: SpecialPowers.DOMWindowUtils.effectivelyThrottlesFrameRequests,
+ }, e.origin);
+};
+</script>
diff --git a/dom/base/test/file_bug1691214.html b/dom/base/test/file_bug1691214.html
new file mode 100644
index 0000000000..e370166598
--- /dev/null
+++ b/dom/base/test/file_bug1691214.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<a id="link-1" href="?1" onclick="window.open(this.href, 'childWin', 'height=300,width=600'); return false;">Open in window.</a>
+<br>
+<a id="link-2" href="?2" onclick="window.open(this.href, 'childWin', 'height=300,width=600'); return false;">Open in window.</a>
diff --git a/dom/base/test/file_bug1700871.html b/dom/base/test/file_bug1700871.html
new file mode 100644
index 0000000000..3bc1808c66
--- /dev/null
+++ b/dom/base/test/file_bug1700871.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<a id="link-1" href="?1" onclick="window.open(this.href, 'childWin', 'height=300,width=600'); return false;">Open in window.</a>
+<form target="frame" method="get">
+ <input type=hidden name=counter value=0>
+ <iframe name="frame" href="file_bug1700871.html"></iframe>
+</form>
+<script>
+ (function submitForm() {
+ if (location.search) {
+ return; // Don't fork-bomb ourselves.
+ }
+
+ let counter = document.querySelector("input");
+ counter.value = ++counter.value;
+ document.querySelector("form").submit();
+ setTimeout(submitForm, 500);
+ }());
+</script>
diff --git a/dom/base/test/file_bug1703472.html b/dom/base/test/file_bug1703472.html
new file mode 100644
index 0000000000..9607663bc3
--- /dev/null
+++ b/dom/base/test/file_bug1703472.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<script>
+ let w = null;
+</script>
+<button id="openWindow" onclick="w = window.open('about:blank', '', 'width=10,height=10')">Open</button>
+<button id="focusWindow" onclick="w.focus()">Focus</button>
diff --git a/dom/base/test/file_bug28293.sjs b/dom/base/test/file_bug28293.sjs
new file mode 100644
index 0000000000..1b3e19402d
--- /dev/null
+++ b/dom/base/test/file_bug28293.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(decodeURIComponent(request.queryString));
+}
diff --git a/dom/base/test/file_bug326337.xml b/dom/base/test/file_bug326337.xml
new file mode 100644
index 0000000000..d328051e74
--- /dev/null
+++ b/dom/base/test/file_bug326337.xml
@@ -0,0 +1 @@
+<data root="yes"/>
diff --git a/dom/base/test/file_bug326337_inner.html b/dom/base/test/file_bug326337_inner.html
new file mode 100644
index 0000000000..01a1929ac8
--- /dev/null
+++ b/dom/base/test/file_bug326337_inner.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=326337
+-->
+<head>
+ <title>Inner file for Bug 326337</title>
+</head>
+<body>
+<script>
+
+document.domain = "example.com";
+
+runTest();
+
+var xhr;
+
+function runTest() {
+ xhr = new XMLHttpRequest();
+ xhr.open("GET", "file_bug326337.xml", true);
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ check(xhr.responseXML.documentElement.getAttribute("root"));
+ SpecialPowers.spawn(parent, [], () => {
+ content.location.hash = "#done";
+ });
+ }
+ }
+ xhr.send(null);
+}
+
+function check(attr) {
+ if (attr != "yes") {
+ SpecialPowers.spawn(parent, [], () => {
+ content.location.hash = "#fail";
+ });
+ throw 1;
+ }
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/file_bug326337_outer.html b/dom/base/test/file_bug326337_outer.html
new file mode 100644
index 0000000000..9d63f72632
--- /dev/null
+++ b/dom/base/test/file_bug326337_outer.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<body>
+<iframe id="inner" src="http://test1.example.com/tests/dom/base/test/file_bug326337_inner.html"></iframe>
+<script>
+var t = setInterval(doCheck, 300);
+function doCheck() {
+ if (location.hash) {
+ clearInterval(t);
+ window.opener.finishTest(location.hash);
+ }
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_bug357450.js b/dom/base/test/file_bug357450.js
new file mode 100644
index 0000000000..6d0d703e78
--- /dev/null
+++ b/dom/base/test/file_bug357450.js
@@ -0,0 +1,74 @@
+/** Test for Bug 357450 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function testGetElements(root, classtestCount) {
+ ok(root.getElementsByClassName, "getElementsByClassName exists");
+ is(
+ typeof root.getElementsByClassName,
+ "function",
+ "getElementsByClassName is a function"
+ );
+
+ var nodes = root.getElementsByClassName("f");
+
+ is(typeof nodes.item, "function");
+ is(typeof nodes.length, "number");
+ is(nodes.length, 0, "string with no matching class should get an empty list");
+
+ nodes = root.getElementsByClassName("foo");
+ ok(nodes, "should have nodelist object");
+
+ // HTML5 says ints are allowed in class names
+ // should match int class
+
+ nodes = root.getElementsByClassName("1");
+ is(nodes[0], $("int-class"), "match integer class name");
+ nodes = root.getElementsByClassName([1]);
+ is(nodes[0], $("int-class"), "match integer class name 2");
+ nodes = root.getElementsByClassName(["1 junk"]);
+
+ is(nodes.length, 0, "two classes, but no elements have both");
+
+ nodes = root.getElementsByClassName("test1");
+ is(nodes[0], $("test1"), "Id and class name turn up the same node");
+ nodes = root.getElementsByClassName("test1 test2");
+ is(nodes.length, 0, "two classes, but no elements have both");
+
+ // WHATWG examples
+ nodes = document.getElementById("example").getElementsByClassName("aaa");
+ is(nodes.length, 2, "returns 2 elements");
+
+ nodes = document.getElementById("example").getElementsByClassName("ccc bbb");
+ is(
+ nodes.length,
+ 1,
+ "only match elements that have all the classes specified in that array. tokenize string arg."
+ );
+ is(nodes[0], $("p3"), "matched tokenized string");
+
+ nodes = document.getElementById("example").getElementsByClassName("");
+ is(nodes.length, 0, "class name with empty string shouldn't return nodes");
+
+ nodes = root.getElementsByClassName({});
+ ok(nodes, "bogus arg shouldn't be null");
+ is(typeof nodes.item, "function");
+ is(typeof nodes.length, "number");
+ is(nodes.length, 0, "bogus arg should get an empty nodelist");
+}
+
+addLoadEvent(function () {
+ if (document.getElementsByName) {
+ var anchorNodes = document.getElementsByName("nametest");
+ is(anchorNodes.length, 1, "getElementsByName still works");
+ is(
+ anchorNodes[0].getAttribute("name"),
+ "nametest",
+ "getElementsByName still works"
+ );
+ }
+ testGetElements($("content"), 1);
+ testGetElements(document.documentElement, 3);
+ testGetElements(document, 3);
+});
+addLoadEvent(SimpleTest.finish);
diff --git a/dom/base/test/file_bug416317.xhtml b/dom/base/test/file_bug416317.xhtml
new file mode 100644
index 0000000000..e46c650cb1
--- /dev/null
+++ b/dom/base/test/file_bug416317.xhtml
@@ -0,0 +1,1468 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg"
+ xml:lang="en" lang="en" dir="ltr" id="html" class="unitTest" title=":root selector">
+<head>
+ <title>selectorTest</title>
+ <!-- (c) Disruptive Innovations 2008 -->
+ <style type="text/css">
+ /* TEST 0 : BASIC TESTS */
+ /* element type selector */
+ body { background-color: red; margin: 10px; padding: 10px; color: red; font-family: sans-serif }
+ div { background-color: red; color: red; }
+ div.header { background-color: #e0e0e0; color: black; padding: 10px; margin-bottom: 10px;}
+ /* class selector */
+ .unitTest { width: 10px; background-color: red; color: red; margin: 0px; margin-right: 2px; float: left; }
+ .test { margin-bottom: 2px; background-color: green; color: green; }
+ /* group of selectors */
+ .unitTest, .test { height: 10px; }
+
+ .UI > * { float: left }
+ .UI { clear: both; height: auto; padding-top: 6px;}
+ .tilda { clear: both; height: auto; padding-top: 6px;}
+ .plus { clear: both; height: auto; padding-top: 6px;}
+
+ h1, p { width: 500px; color: #000; }
+ a { color: #000; }
+ #results { background: #FFF; width: 600px; padding: 10px 40px; color: #000; font-size: 11px; line-height: 1.3em; }
+ #root, #root2, #root3 { display: none; }
+
+ /* init */
+ .blox16 { background-color: red; }
+ .blox17 { background-color: red; }
+ .lastChild > p { background-color: red; }
+ .firstOfType > p { background-color: red }
+ .lastOfType > p { background-color: red }
+ .empty > .isEmpty { color: red; }
+ html { background-color: red; }
+ </style>
+ <span type="text/test" id="test"><![CDATA[
+ /* :target selector */
+ .target :target { background-color: lime; }
+
+ /* test 1 : childhood selector */
+ html > body { background-color: green; }
+ .test > .blox1 { background-color: lime; }
+
+ /* test 2 : attribute existence selector */
+ /* attribute with a value */
+ .blox2[align] { background-color: lime; }
+ /* attribute with empty value */
+ .blox3[align] { background-color: lime; }
+ /* attribute with almost similar name */
+ .blox4, .blox5 { background-color: lime }
+ .blox4[align], .blox5[align] { background-color: red; }
+
+ /* test3 : attribute value selector */
+ .blox6[align="center"] { background-color: lime; }
+ .blox6[align="c"] { background-color: red; }
+ .blox6[align="centera"] { background-color: red; }
+ .blox6[foo="\e9"] { background-color: lime; }
+ .blox6[\_foo="\e9"] { background-color: lime; }
+
+ /* test 4 : [~=] */
+ .blox7[class~="foo"] { background-color: lime; }
+ .blox8, .blox9, .blox10 { background-color: lime; }
+ .blox8[class~=""] { background-color: red; }
+ .blox9[foo~=""] { background-color: red; }
+ .blox10[foo~="foo"] { background-color: red; }
+
+ /* test5 [^=] */
+ .attrStart > .t3 { background-color: lime; }
+ .attrStart > .t1[class^="unit"] { background-color: lime; }
+ .attrStart > .t2 { background-color: lime; }
+ .attrStart > .t2[class^="nit"] { background-color: red; }
+ .attrStart > .t3[align^=""] { background-color: red; }
+ .attrStart > .t4[foo^="\e9"] { background-color: lime; }
+
+ /* test6 [$=] */
+ .attrEnd > .t3 { background-color: lime; }
+ .attrEnd > .t1[class$="t1"] { background-color: lime; }
+ .attrEnd > .t2 { background-color: lime; }
+ .attrEnd > .t2[class$="unit"] { background-color: red; }
+ .attrEnd > .t3[align$=""] { background-color: red; }
+ .attrEnd > .t4[foo$="\e9"] { background-color: lime; }
+
+ /* test7 [*=] */
+ .attrMiddle > .t3 { background-color: lime; }
+ .attrMiddle > .t1[class*="t t"] { background-color: lime; }
+ .attrMiddle > .t2 { background-color: lime; }
+ .attrMiddle > .t2[class*="a"] { background-color: red; }
+ .attrMiddle > .t3[align*=""] { background-color: red; }
+ .attrMiddle > .t4[foo*="\e9"] { background-color: lime; }
+
+ /* :first-child tests */
+ .firstChild .unitTest:first-child { background-color: lime; }
+ .blox12:first-child { background-color: red; }
+ .blox13:first-child { background-color: red; }
+ .blox12, .blox13 { background-color: lime }
+
+ /* :root tests */
+ :root { background-color: green; }
+
+ /* :scope tests */
+ :scope { background-color: green; }
+
+ /* :nth-child(n) tests */
+ .nthchild1 > :nth-last-child(odd) { background-color: lime; }
+ .nthchild1 > :nth-child(odd) { background-color: lime; }
+
+ .nthchild2 > :nth-last-child(even) { background-color: lime; }
+ .nthchild2 > :nth-child(even) { background-color: lime; }
+
+ .nthchild3 > :nth-child(3n+2) { background-color: lime; }
+ .nthchild3 > :nth-last-child(3n+1) { background-color: lime; }
+ .nthchild3 > :nth-last-child(3n+3) { background-color: lime; }
+
+ .nthoftype1 > div:nth-of-type(odd) { background-color: lime; }
+ .nthoftype1 > div:nth-last-of-type(odd) { background-color: lime; }
+ .nthoftype1 > p { background-color: green; }
+
+ .nthoftype2 > div:nth-of-type(even) { background-color: lime; }
+ .nthoftype2 > div:nth-last-of-type(even) { background-color: lime; }
+ .nthoftype2 > p { background-color: green; }
+
+ .nthoftype3 > div:nth-of-type(3n+1) { background-color: lime; }
+ .nthoftype3 > div:nth-last-of-type(3n+1) { background-color: lime; }
+ .nthoftype3 > div:nth-last-of-type(3n+2) { background-color: lime; }
+ .nthoftype3 > p { background-color: green; }
+
+ /* :not() tests */
+ .blox14:not(span) { background-color: lime; }
+ .blox15:not([foo="blox14"]) { background-color: lime; }
+ .blox16:not(.blox15) { background-color: lime; }
+
+ /* :only-of-type tests */
+ .blox17:only-of-type { background-color: lime; }
+ .blox18:only-of-type { background-color: red; }
+ .blox18:not(:only-of-type) { background-color: lime; }
+
+ /* :last-child tests */
+ .lastChild > :last-child { background-color: lime }
+ .lastChild > :not(:last-child) { background-color: lime }
+
+ /* :first-of-type tests */
+ .firstOfType > *:first-of-type { background-color: lime; }
+ *.firstOfType > :not(:first-of-type) { background-color: lime; }
+
+ /* :last-of-type tests */
+ .lastOfType > *:last-of-type { background-color: lime; }
+ *.lastOfType > :not(:last-of-type) { background-color: lime; }
+
+ /* :only-child tests */
+ .onlyChild > *:not(:only-child) { background-color: lime; }
+ .onlyChild > .unitTest > *:only-child { background-color: lime; }
+
+ /* :only-of-type tests */
+ .onlyOfType *:only-of-type { background-color: lime; }
+ .onlyOfType *:not(:only-of-type) { background-color: lime; }
+
+ /* :empty tests */
+ .empty > *.isEmpty:empty { background-color: lime; color: lime; }
+ .empty > .isNotEmpty { background-color: blue; color: blue; }
+ .empty > .isNotEmpty:empty { background-color: red; color: red; }
+ .empty > .isNotEmpty:not(:empty) { background-color: lime; color: lime; }
+
+ /* :lang() tests */
+ .lang :lang(en) { background-color: lime; }
+ .lang :lang(fr) { background-color: lime; }
+ .lang .t1 { background-color: blue; }
+ .lang .t1:lang(es) { background-color: lime; }
+ .lang :lang(es-AR) { background-color: red; }
+
+ /* [|=] tests */
+ .attrLang .t1 { background-color: lime; }
+ .attrLang .t1[lang|="en"] { background-color: red; }
+ .attrLang [lang|="fr"] { background-color: lime; }
+ .attrLang .t2[lang|="en"] { background-color: lime; }
+ .attrLang .t3 { background-color: blue; }
+ .attrLang .t3[lang|="es"] { background-color: lime; }
+ .attrLang [lang|="es-AR"] { background-color: red; }
+
+ /* UI tests */
+ .UI .t1:enabled > .unitTest { background-color: lime; }
+ .UI .t2:disabled > .unitTest { background-color: lime; }
+ .UI .t3:checked + div { background-color: lime; }
+ .UI .t4:not(:checked) + div { background-color: lime; }
+
+ /* ~ combinator tests */
+ .tilda .t1 { background-color: white; }
+ .tilda .t1 ~ .unitTest { background-color: lime; }
+ .tilda .t1:hover ~ .unitTest { background-color: red; }
+
+ /* ~ combinator tests */
+ .plus .t1, .plus .t2 { background-color: white; }
+ .plus .t1 + .unitTest + .unitTest { background-color: lime; }
+ .plus .t1:hover + .unitTest + .unitTest { background-color: red; }
+ ]]></span>
+ <span type="text/test" id="error">
+ /* Tests from http://www.w3.org/Style/CSS/Test/CSS3/Selectors/20060307/html/index.html */
+
+ div, { background: red; }
+ .5cm { background: red; }
+ [*=test] { background: red; }
+ [*|*=test] { background: red; }
+
+ div:subject { background: red; }
+ :canvas { background: red; }
+ :viewport { background: red; }
+ :window { background: red; }
+ :menu { background: red; }
+ :table { background: red; }
+ :select { background: red; }
+ ::canvas { background: red; }
+ ::viewport { background: red; }
+ ::window { background: red; }
+ ::menu { background: red; }
+ ::table { background: red; }
+ ::select { background: red; }
+
+ ..test { background: red; color: yellow; }
+ .foo..quux { background: red; color: yellow; }
+ .bar. { background: red; color: yellow; }
+ </span>
+ <script><![CDATA[
+ /* eslint-disable no-shadow */
+
+ window.onload = function() {
+ doTest();
+ }
+
+ function doTest(){
+ if ( !window.location.hash.includes("target") )
+ window.location.hash = "#target";
+
+ var root = document.getElementById("root");
+ var root2 = document.getElementById("root2");
+ var root3 = document.getElementById("root3");
+ var results = [];
+ var tests = 0, passed = 0;
+ var cache = {};
+
+ var css = document.getElementById("test").firstChild.nodeValue.split("\n");
+ for ( let i = 0; i < css.length; i++ ) {
+ css[i] = css[i].replace(/\/\*.*?\*\//g, "")
+ .replace(/^\s*|\s*$/g, "").split(/\s*{/);
+ }
+
+ var ecss = document.getElementById("error").firstChild.nodeValue.split("\n");
+ for ( let i = 0; i < ecss.length; i++ ) {
+ ecss[i] = ecss[i].replace(/\/\*.*?\*\//g, "")
+ .replace(/^\s*|\s*$/g, "").split(/\s*{/);
+ }
+
+ var namespaceCheck = {};
+
+ var badNamespace = [
+ {},
+ null,
+ undefined,
+ ];
+
+ interfaceCheck(root, "Element");
+ runTest( css, "Element", root, true );
+ check( "Inside Element", root, true, false );
+ cacheCheck( "Element", root );
+ check( "Outside Element", root2, passed === 0 ? "autofail" : false, false );
+ runTest( ecss, "SyntaxError: Element", root, false );
+ jqTests("Element", root3, "querySelectorAll");
+
+ var root4 = root2.cloneNode(true);
+ interfaceCheck(root4, "Disconnected Element");
+ runTest( css, "Disconnected Element", root4, true );
+ check( "Disconnected Element", root4, true, true );
+ cacheCheck( "Disconnected Element", root4 );
+ runTest( ecss, "SyntaxError: Disconnected Element", root4, false );
+ jqTests("Disconnected Element", root3.cloneNode(true), "querySelectorAll");
+ var newRoot = document.createElement("nosuchtag");
+ newRoot.appendChild(root3.cloneNode(true));
+ jqTests("Disconnected Element scoping", newRoot, "querySelectorAll");
+
+ var fragment = document.createDocumentFragment();
+ fragment.appendChild( root2.cloneNode(true) );
+
+ interfaceCheck(fragment, "Fragment");
+ runTest( css, "Fragment", fragment, true );
+ check( "Fragment", fragment, true, true );
+ runTest( ecss, "SyntaxError: Fragment", fragment, false );
+ cacheCheck( "Fragment", fragment );
+
+ root.remove( );
+
+ interfaceCheck(document, "Document");
+ runTest( css, "Document", document, true );
+ check( "Document", document, true, false );
+ runTest( ecss, "SyntaxError: Document", document, false );
+ jqTests("Document", document, "querySelectorAll");
+ cacheCheck( "Document", document );
+
+ done();
+
+ function interfaceCheck(obj, type){
+ var q = typeof obj.querySelector === "function";
+ assert( q, type + " supports querySelector" );
+ var qa = typeof obj.querySelectorAll === "function";
+ assert( qa, type + " supports querySelectorAll" );
+ return q && qa;
+ }
+
+ function done(){
+ if (window.parent && window.parent.SimpleTest) {
+ window.parent.SimpleTest.finish();
+ } else {
+ var r = document.getElementById("results");
+ var li = document.createElement("li");
+ var b = document.createElement("b");
+ b.appendChild( document.createTextNode( ((passed / tests) * 100).toFixed(1) + "%" ) );
+ li.appendChild( b );
+ li.appendChild( document.createTextNode( ": " + passed + " passed, " + (tests - passed) + " failed" ) );
+ r.appendChild( li );
+
+ for ( let i = 0; i < results.length; i++ ) {
+ var li = document.createElement("li");
+ var span = document.createElement("span");
+ span.style.color = (results[i][0] === "FAIL" ? "red" : "green");
+ span.appendChild( document.createTextNode( results[i][0] ) );
+ li.appendChild( span );
+ li.appendChild( document.createTextNode( " " + results[i][1] ) );
+ r.appendChild( li );
+ }
+ }
+ }
+
+ function cacheCheck( type, root ) {
+ try {
+ var pre = root.querySelectorAll( "div" ), preLength = pre.length;
+
+ var div = document.createElement("div");
+ (root.body || root).appendChild( div );
+
+ var post = root.querySelectorAll( "div" ), postLength = post.length;
+
+ assert( pre.length == preLength, type + ": StaticNodeList" );
+ assert( post.length != pre.length, type + ": StaticNodeList" );
+ } catch(e) {
+ assert( false, type + ": StaticNodeList" );
+ assert( false, type + ": StaticNodeList" );
+ }
+
+ if ( div )
+ (root.body || root).removeChild( div );
+ }
+
+
+ function runTest( css, type, root, expect ) {
+ var pass = false;
+ try {
+ root.querySelectorAll("");
+ } catch(e){ pass = e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR; }
+ assert( pass, type + ".querySelectorAll Empty String" );
+
+ pass = false;
+ try {
+ pass = root.querySelectorAll(null).length === 0;
+ } catch(e){ pass = false; }
+ assert( pass, type + ".querySelectorAll null" );
+
+ pass = false;
+ try {
+ pass = root.querySelectorAll(undefined).length === 0;
+ } catch(e){ pass = false; }
+ assert( pass, type + ".querySelectorAll undefined" );
+
+ pass = false;
+ try {
+ if ( root.querySelectorAll )
+ root.querySelectorAll();
+ } catch(e){ pass = true; }
+ assert( pass, type + ".querySelectorAll no value" );
+
+ pass = false;
+ try {
+ root.querySelector("");
+ } catch(e){ pass = e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR; }
+ assert( pass, type + ".querySelector Empty String" );
+
+ pass = false;
+ try {
+ pass = root.querySelector(null) === null;
+ } catch(e){ pass = false; }
+ assert( pass, type + ".querySelector null" );
+
+ pass = false;
+ try {
+ pass = root.querySelector(undefined) === null;
+ } catch(e){ pass = false; }
+ assert( pass, type + ".querySelector undefined" );
+
+ pass = false;
+ try {
+ if ( root.querySelector )
+ root.querySelector();
+ } catch(e){ pass = true; }
+ assert( pass, type + ".querySelector no value" );
+
+ for ( let i = 0; i < css.length; i++ ) {
+ var test = css[i];
+ if ( test.length == 2 ) {
+ var query = test[0], color = test[1].match(/: ([^\s;]+)/)[1];
+
+ try {
+ var found = root.querySelectorAll(query);
+
+ for ( var f = 0; f < found.length; f++ ) {
+ found[f].style.backgroundColor = color;
+ }
+
+ var pass = color != "red" || found.length === 0;
+
+ assert(expect && pass, type + ".querySelectorAll: " + query);
+ } catch(e){
+ var pass = !expect && e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR || false;
+ assert(pass, type + ".querySelectorAll: " + query);
+ }
+
+ if ( expect ) {
+ var pass = false;
+
+ try {
+ var found2 = root.querySelectorAll( " \t\r\n " + query + " \t\r\n " );
+ pass = found2.length == found.length;
+ } catch(e) {}
+
+ assert(pass, type + ".querySelectorAll Whitespace Trim: " + query);
+ }
+
+ try {
+ var single = root.querySelector(query);
+
+ var pass = !found.length && single === null ||
+ found.length && found[0] == single;
+
+ assert(expect, type + ".querySelector: " + query);
+ } catch(e){
+ var pass = !expect && e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR || false;
+ assert(pass, type + ".querySelector: " + query);
+ }
+ }
+ }
+ }
+
+ function check( type, root, expect, fragment ){
+ var walker = document.createTreeWalker( root, NodeFilter.SHOW_ELEMENT, { acceptNode(){ return 1; } } );
+
+ while ( walker.nextNode() ) {
+ var div = walker.currentNode;
+ if ( (div.getAttribute("class") || "").toString().indexOf("unitTest") > -1 &&
+ (!fragment || div.getAttribute("id") !== "nofragment") ) {
+ // If we're display:none, we need to toggle that when doing computed
+ // style.
+ var needToggle =
+ (window.frameElement &&
+ window.frameElement.style.display == "none");
+ if (needToggle) {
+ if ((div.getAttribute("class") || "").toString().indexOf("skipWhenToggling") > -1) {
+ continue;
+ }
+ window.frameElement.style.display = "";
+ // make sure it kicks in immediately
+ document.body.offsetWidth;
+ }
+ var view = document.defaultView.getComputedStyle(div);
+ var bg = view.getPropertyValue("background-color") || div.style.backgroundColor;
+ if (needToggle) {
+ window.frameElement.style.display = "none";
+ // make sure it kicks in immediately
+ document.body.offsetWidth;
+ }
+
+ var pass = bg && !bg.includes("(255, 0, 0") && !bg.includes("#ff0000") && !bg.includes("red");
+ //var pass = bg && bg.indexOf("(255, 0, 0") == -1 && bg.indexOf("#ff0000") == -1;
+ assert(pass === expect, type + ": " + (div.title || div.parentNode.title));
+ }
+ }
+ }
+
+ function assert(pass, title) {
+ // Update |passed| no matter what: some tests depend on this
+ passed += (pass ? 1 : 0);
+
+ if (window.parent && window.parent.SimpleTest) {
+ window.parent.SimpleTest.ok(pass, title);
+ } else {
+ results.push([ (!pass ? "FAIL" : "PASS"), title ]);
+ tests++;
+ }
+ }
+
+ function jqTests(type, root, select) {
+
+ function query(q, resolver){
+ try {
+ return root[select](q, resolver);
+ } catch(e){
+ if ( e.message.indexOf("ERR") > -1 ||
+ (e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR) )
+ throw e;
+ }
+ }
+
+ var all = query("*");
+
+ function checkMatchesSelector(results, q) {
+ var key = +new Date + ":" + Math.random();
+
+ function report(item, shouldMatch) {
+ assert( item.matches(q) === shouldMatch,
+ item + (shouldMatch ? "does not match" : "matches")
+ + " selector '" + q + "'" );
+ }
+
+ for (var i = 0; i < results.length; i++) {
+ var item = results.item(i);
+ item[key] = true;
+ report( item, true );
+ }
+
+ for (var stride = 15, // reduce test spam
+ i = Math.round(Math.random() * stride);
+ i < all.length; i += stride)
+ {
+ var item = all.item(i),
+ shouldMatch = !!item[key];
+ report( item, shouldMatch );
+ }
+
+ for (var i = 0; i < results.length; i++)
+ delete results.item(i)[key];
+ }
+
+ function t( name, q, ids, restrict, ids2 ) {
+ var pass = true;
+
+ if ( restrict === false && root != document )
+ return;
+
+ var namespaced = /\|[^=]/.test( q );
+ var prepend = namespaced ? "xHTML|*#root3 " : "#root3 ";
+ q = (restrict === false || restrict === ":root" ||
+ restrict === ":scope" ? "" : prepend) +
+ q.replace(/,/g, ", " + prepend);
+ var nq = q.replace(/>/g, "&gt;").replace(/</g, "&lt;");
+
+ if ( namespaced ) {
+ for ( var i = 0; i < badNamespace.length; i++ ) {
+ var resolver = badNamespace[i], pass = false, results = null;
+
+ try {
+ results = query(q, resolver);
+ } catch(e) {
+ pass = (e.message === "bad ERROR" ||
+ (e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR));
+ }
+
+ assert( pass, type + ": " + name + " Bad Resolver #" + (i+1) + " (" + nq + ")" +
+ (pass ? "" : " Expected: " + extra(ids) + " Received: " + extra(results)) );
+ }
+ } else {
+ var pass = false;
+
+ try {
+ var results = query(q);
+ pass = hasPassed( results, ids );
+ } catch(e) {
+ pass = e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR;
+ }
+
+ assert( pass, type + ": " + name + " (" + nq + ")" +
+ (pass ? "" : " Expected: " + extra(ids) + " Received: " + extra(results)) );
+
+ // For now, don't use checkMatchesSelector when
+ // restrict === ":scope" because we have no way to hand the
+ // right scope to it yet.
+ if (results && restrict !== ":scope")
+ checkMatchesSelector( results, q );
+ }
+
+ function hasPassed(results, ids){
+ var pass = (results && results.length == ids.length) || (!results && !ids);
+
+ if ( ids && results ) {
+ for ( var i = 0; ids && i < ids.length; i++ ) {
+ if ( ids[i] !== results[i].getAttribute("id") ) {
+ pass = false;
+ }
+ }
+ } else {
+ pass = false;
+ }
+
+ return pass;
+ }
+
+ function extra(results){
+ var extra = " [";
+ if ( results ) {
+ for ( var i = 0; i < results.length; i++ ) {
+ extra += (extra.length > 2 ? "," : "") + "'" + (results[i].id || results[i]) + "'";
+ }
+ }
+
+ extra += "]";
+ return extra;
+ }
+ }
+
+ t( "SVG", "*|svg", ["svg1","svg2","svg3"] );
+ t( "SVG", "svg|svg", ["svg2","svg3"] );
+ t( "SVG", "svg|svg *|circle", ["circle2","circle3"] );
+ t( "SVG", "svg|svg svg|circle", ["circle2","circle3"] );
+ t( "SVG", "xHTML|div *|svg", ["svg1","svg2","svg3"] );
+ t( "SVG", "div svg|svg", ["svg2","svg3"] );
+ t( "SVG", "xHTML|div svg|svg", ["svg2","svg3"] );
+ t( "SVG", "xHTML|div svg|svg *|circle", ["circle2","circle3"] );
+ t( "SVG", "xHTML|div svg *|circle", ["circle1","circle2","circle3"], true, ["circle1"] );
+ t( "SVG", "xHTML|div svg|svg svg|circle", ["circle2","circle3"] );
+
+ t( "Element Selector", "xHTML|p", ["firstp","ap","sndp","en","sap","first"] );
+ t( "Parent Element", "xHTML|div p", ["firstp","ap","sndp","en","sap","first"] );
+ t( "Parent Element", "xHTML|div xHTML|p", ["firstp","ap","sndp","en","sap","first"] );
+ t( "Parent Element", "*|div xHTML|p", ["firstp","ap","sndp","en","sap","first"] );
+ t( "Parent Element", "*|div *|p", ["firstp","ap","sndp","en","sap","first"] );
+ t( "Child", "xHTML|p > xHTML|a", ["simon1","google","groups","mark","yahoo","simon"] );
+ t( "Adjacent", "xHTML|a + xHTML|a", ["groups"] );
+ t( "Adjacent", "xHTML|a + a", ["groups"] );
+ t( "Nth-child", "xHTML|*#form xHTML|*#select1 xHTML|option:nth-child(3)", ["option1c"] );
+
+ assert( all && all.length > 30, type + ": Select all" );
+ var good = all && all.length;
+ for ( var i = 0; all && i < all.length; i++ )
+ if ( all[i].nodeType != 1 )
+ good = false;
+ assert( good, type + ": Select all elements, no comment nodes" );
+
+ if ( root == document ) {
+ t( ":root Selector", ":root", ["html"], false );
+ t( ":scope Selector", ":scope", ["html"], ":scope" );
+ } else {
+ t( ":root Selector", ":root", [], ":root" );
+ if (root.localName != "nosuchtag") {
+ t( ":scope Selector", ":scope > nosuchtag",
+ [ "outerbogustag" ], ":scope");
+ }
+ t( ":scope Selector", ":scope nosuchtag nosuchtag",
+ [ "innerbogustag" ], ":scope");
+
+ if ( !root.parentNode ) {
+ t( ":root All Selector", ":root *", [], ":root" );
+ }
+ }
+
+ if ( root.parentNode || root == document ) {
+ assert( query(":root *").length == query("*").length - (root == document ? 1 : 0), type + ": :root All Selector" );
+ }
+ assert( query(":scope *").length == query("*").length - (root == document ? 1 : 0), type + ": :scope All Selector" );
+
+ t( "Element Selector", "p", ["firstp","ap","sndp","en","sap","first"] );
+ t( "Element Selector", "body", ["body"], false );
+ t( "Element Selector", "html", ["html"], false );
+ t( "Parent Element", "div p", ["firstp","ap","sndp","en","sap","first"] );
+ var param = query("#object1 param");
+ assert( param && param.length == 2, type + ": Object/param as context" );
+
+ var l = query("#length");
+ assert( l && l.length, type + ': &lt;input name="length"&gt; cannot be found under IE' );
+ var lin = query("#lengthtest input");
+ assert( lin && lin.length, type + ': &lt;input name="length"&gt; cannot be found under IE' );
+
+ t( "Broken Selector", "[" );
+ t( "Broken Selector", "(" );
+ t( "Broken Selector", "{" );
+ t( "Broken Selector", "<" );
+ t( "Broken Selector", "()" );
+ t( "Broken Selector", "<>" );
+ t( "Broken Selector", "{}" );
+
+ t( "ID Selector", "#body", ["body"], false );
+ t( "ID Selector w/ Element", "body#body", ["body"], false );
+ t( "ID Selector w/ Element", "ul#first", [] );
+ t( "ID selector with existing ID descendant", "#firstp #simon1", ["simon1"] );
+ t( "ID selector with nonexistent descendant", "#firstp #foobar", [] );
+
+ t( "ID selector using UTF8", "#å°åŒ—TaÌibeÌŒi", ["å°åŒ—TaÌibeÌŒi"] );
+ t( "Multiple ID selectors using UTF8", "#å°åŒ—TaÌibeÌŒi, #å°åŒ—", ["å°åŒ—TaÌibeÌŒi","å°åŒ—"] );
+ t( "Descendant ID selector using UTF8", "div #å°åŒ—", ["å°åŒ—"] );
+ t( "Child ID selector using UTF8", "form > #å°åŒ—", ["å°åŒ—"] );
+
+ t( "Escaped ID", "#foo\\:bar", ["foo:bar"] );
+ t( "Escaped ID", "#test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+ t( "Descendant escaped ID", "div #foo\\:bar", ["foo:bar"] );
+ t( "Descendant escaped ID", "div #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+ t( "Child escaped ID", "form > #foo\\:bar", ["foo:bar"] );
+ t( "Child escaped ID", "form > #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+
+ t( "ID Selector, child ID present", "#form > #radio1", ["radio1"] ); // bug #267
+ t( "ID Selector, not an ancestor ID", "#form #first", [] );
+ t( "ID Selector, not a child ID", "#form > #option1a", [] );
+
+ t( "All Children of ID", "#foo > *", ["sndp", "en", "sap"] );
+ t( "All Children of ID with no children", "#firstUL > *", [] );
+
+ t( "ID selector with nonexistent ancestor", "#asdfasdf #foobar", [] ); // bug #986
+
+ //t( "body div#form", [], "ID selector within the context of another element" );
+
+ t( "Class Selector", ".blog", ["mark","simon"] );
+ t( "Class Selector", ".blog.link", ["simon"] );
+ t( "Class Selector w/ Element", "a.blog", ["mark","simon"] );
+ t( "Parent Class Selector", "p .blog", ["mark","simon"] );
+
+ t( "Class selector using UTF8", ".å°åŒ—TaÌibeÌŒi", ["utf8class1"] );
+ t( "Class selector using UTF8", ".å°åŒ—", ["utf8class1","utf8class2"] );
+ t( "Class selector using UTF8", ".å°åŒ—TaÌibeÌŒi.å°åŒ—", ["utf8class1"] );
+ t( "Class selector using UTF8", ".å°åŒ—TaÌibeÌŒi, .å°åŒ—", ["utf8class1","utf8class2"] );
+ t( "Descendant class selector using UTF8", "div .å°åŒ—TaÌibeÌŒi", ["utf8class1"] );
+ t( "Child class selector using UTF8", "form > .å°åŒ—TaÌibeÌŒi", ["utf8class1"] );
+
+ t( "Escaped Class", ".foo\\:bar", ["foo:bar"] );
+ t( "Escaped Class", ".test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+ t( "Descendant scaped Class", "div .foo\\:bar", ["foo:bar"] );
+ t( "Descendant scaped Class", "div .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+ t( "Child escaped Class", "form > .foo\\:bar", ["foo:bar"] );
+ t( "Child escaped Class", "form > .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
+
+ t( "Comma Support", "a.blog, p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+ t( "Comma Support", "a.blog , p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+ t( "Comma Support", "a.blog ,p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+ t( "Comma Support", "a.blog,p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+
+ t( "Outer Whitespace", " a.blog,p", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+ t( "Outer Whitespace", "a.blog,p ", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+ t( "Outer Whitespace", " p,a.blog", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+ t( "Outer Whitespace", "p,a.blog ", ['firstp','ap','mark','sndp','en','sap','simon','first'] );
+
+ t( "Child", "p > a", ["simon1","google","groups","mark","yahoo","simon"] );
+ t( "Child", "p> a", ["simon1","google","groups","mark","yahoo","simon"] );
+ t( "Child", "p >a", ["simon1","google","groups","mark","yahoo","simon"] );
+ t( "Child", "p>a", ["simon1","google","groups","mark","yahoo","simon"] );
+ t( "Child w/ Class", "p > a.blog", ["mark","simon"] );
+ t( "All Children", "code > *", ["anchor1","anchor2"] );
+ t( "All Grandchildren", "p > * > *", ["anchor1","anchor2"] );
+ t( "Adjacent", "a + a", ["groups"] );
+ t( "Adjacent", "a +a", ["groups"] );
+ t( "Adjacent", "a+ a", ["groups"] );
+ t( "Adjacent", "a+a", ["groups"] );
+ t( "Adjacent", "p + p", ["ap","en","sap"] );
+ t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] );
+
+ t( "First Child", "p:first-child", ["firstp","sndp"] );
+ t( "Nth Child", "p:nth-child(1)", ["firstp","sndp"] );
+
+ t( "Last Child", "p:last-child", ["sap"] );
+ t( "Last Child", "a:last-child", ["simon1","anchor1","mark","yahoo","anchor2","simon"] );
+
+ t( "Nth-child", "#main form#form > *:nth-child(2)", ["text2"] );
+ t( "Nth-child", "#main form#form > :nth-child(2)", ["text2"] );
+
+ t( "Nth-child", "#form #select1 option:nth-child(3)", ["option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(0n+3)", ["option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(1n+0)", ["option1a", "option1b", "option1c", "option1d"] );
+ t( "Nth-child", "#form #select1 option:nth-child(1n)", ["option1a", "option1b", "option1c", "option1d"] );
+ t( "Nth-child", "#form #select1 option:nth-child(n)", ["option1a", "option1b", "option1c", "option1d"] );
+ t( "Nth-child", "#form #select1 option:nth-child(even)", ["option1b", "option1d"] );
+ t( "Nth-child", "#form #select1 option:nth-child(odd)", ["option1a", "option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(2n)", ["option1b", "option1d"] );
+ t( "Nth-child", "#form #select1 option:nth-child(2n+1)", ["option1a", "option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n)", ["option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n+1)", ["option1a", "option1d"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n+2)", ["option1b"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n+3)", ["option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n-1)", ["option1b"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n-2)", ["option1a", "option1d"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n-3)", ["option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(3n+0)", ["option1c"] );
+ t( "Nth-child", "#form #select1 option:nth-child(-n+3)", ["option1a", "option1b", "option1c"] );
+
+ t( "Attribute Exists", "a[title]", ["google"] );
+ t( "Attribute Exists", "*[title]", ["google"] );
+ t( "Attribute Exists", "[title]", ["google"] );
+
+ t( "Attribute Equals", "a[rel='bookmark']", ["simon1"] );
+ t( "Attribute Equals", 'a[rel="bookmark"]', ["simon1"] );
+ t( "Attribute Equals", "a[rel=bookmark]", ["simon1"] );
+ t( "Multiple Attribute Equals", "#form input[type='hidden'],#form input[type='radio']", ['radio1','radio2','hidden1'] );
+ t( "Multiple Attribute Equals", "#form input[type=\"hidden\"],#form input[type='radio']", ['radio1','radio2','hidden1'] );
+ t( "Multiple Attribute Equals", "#form input[type=hidden],#form input[type=radio]", ['radio1','radio2','hidden1'] );
+
+ t( "Attribute selector using UTF8", "span[lang=中文]", ["å°åŒ—"] );
+
+ t( "Attribute Begins With", "a[href ^= 'http://www']", ["google","yahoo"] );
+ t( "Attribute Ends With", "a[href $= 'org/']", ["mark"] );
+ t( "Attribute Contains", "a[href *= 'google']", ["google","groups"] );
+
+ // t("Select options via [selected]", "#select1 option[selected]", ["option1a"] );
+ t("Select options via [selected]", "#select1 option[selected]", [] );
+ t("Select options via [selected]", "#select2 option[selected]", ["option2d"] );
+ t("Select options via [selected]", "#select3 option[selected]", ["option3b", "option3c"] );
+
+ t( "Grouped Form Elements", "input[name='foo[bar]']", ["hidden2"] );
+
+ t( ":not() Existing attribute", "#form select:not([multiple])", ["select1", "select2"]);
+ t( ":not() Equals attribute", "#form select:not([name=select1])", ["select2", "select3"]);
+ t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", ["select2", "select3"]);
+
+ t( "First Child", "p:first-child", ["firstp","sndp"] );
+ t( "Last Child", "p:last-child", ["sap"] );
+ t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2"] );
+ t( "Empty", "ul:empty", ["firstUL"] );
+ //t( "Enabled UI Element", "#form input:enabled", ["text1","radio1","radio2","check1","check2","hidden2","name"] );
+ t( "Disabled UI Element", "#form input:disabled", ["text2"] );
+ t( "Checked UI Element", "#form input:checked", ["radio2","check1"] );
+ t( "Element Preceded By", "p ~ div", ["foo","fx-queue","fx-tests", "moretests"] );
+ t( "Not", "a.blog:not(.link)", ["mark"] );
+ }
+ };
+ ]]></script>
+</head>
+<body id="body" class="unitTest" title="childhood and element type selectors">
+<h1><a href="http://www.w3.org/TR/selectors-api/">Selectors API</a> Test Suite</h1>
+<p>Testrunner by <a href="http://ejohn.org/">John Resig</a>, tests by <a href="http://ejohn.org/">John Resig</a>, <a href="http://disruptive-innovations.com/zoo/css3tests/selectorTest.html">Disruptive Innovations</a>, <a href="http://www.w3.org/Style/CSS/Test/CSS3/Selectors/20060307/html/index.html">W3C CSS Working Group</a>, <a href="http://jquery.com/test/">jQuery JavaScript Library</a>.</p>
+<div id="root">
+ <div class="header">
+ <h3>CSS 3 Selectors tests</h3>
+ <p>(c) <a href="http://www.disruptive-innovations.com">Disruptive Innovations</a> 2008<br/>
+ Last update: 2008-06-06</p>
+ </div>
+
+ <div class="test target">
+ <div class="unitTest skipWhenToggling" id="target" title=":target selector"></div>
+ </div>
+
+ <div class="test">
+ <div class="blox1 unitTest" title="childhood selector"></div>
+ </div>
+
+ <div class="test attributeExistence">
+ <div class="blox2 unitTest" align="center" title="attribute existence selector"></div>
+ <div class="blox3 unitTest" align="" title="attribute existence selector with empty string value"></div>
+ <div class="blox4 unitTest" valign="center" title="attribute existence selector with almost identical attribute"></div>
+ <div class="blox5 unitTest" alignv="center" title="attribute existence selector with almost identical attribute"></div>
+ </div>
+
+ <div class="test attributeValue">
+ <div class="blox6 unitTest" align="center" title="attribute value selector"></div>
+ <div class="blox6 unitTest" foo="&eacute;" title="attribute value selector with an entity in the attribute and an escaped value in the selector"></div>
+ <div class="blox6 unitTest" _foo="&eacute;" title="attribute value selector with an entity in the attribute, an escaped value in the selector, and a leading underscore in the attribute name"></div>
+ </div>
+
+ <div class="test attributeSpaceSeparatedValues">
+ <div class="blox7 foo unitTest" title="[~=] attribute selector"></div>
+ <div class="blox8 unitTest" title="[~=] attribute selector looking for empty string"></div>
+ <div class="blox9 unitTest" foo="" title="[~=] attribute selector looking for empty string in empty attribute"></div>
+ <div class="blox10 unitTest" foo="foobar" title="[~=] attribute selector looking for 'foo' in 'foobar'"></div>
+ </div>
+
+ <div class="test attrStart">
+ <div class="unitTest t1" title="[^=] attribute selector"></div>
+ <div class="unitTest t2" title="[^=] attribute selector"></div>
+ <div class="unitTest t3" align="center" title="[^=] attribute selector looking for empty string"></div>
+ <div class="unitTest t4" foo="&eacute;tagada" title="[^=] attribute selector looking for &eacute;"></div>
+ </div>
+
+ <div class="test attrEnd">
+ <div class="unitTest t1" title="[$=] attribute selector"></div>
+ <div class="unitTest t2" title="[$=] attribute selector"></div>
+ <div class="unitTest t3" align="center" title="[$=] attribute selector looking for empty string"></div>
+ <div class="unitTest t4" foo="tagada&eacute;" title="[$=] attribute selector looking for &eacute;"></div>
+ </div>
+
+ <div class="test attrMiddle">
+ <div class="unitTest t1" title="[*=] attribute selector"></div>
+ <div class="unitTest t2" title="[*=] attribute selector"></div>
+ <div class="unitTest t3" align="center" title="[*=] attribute selector looking for empty string"></div>
+ <div class="unitTest t4" foo="tagada&eacute;foo" title="[*=] attribute selector looking for &eacute;"></div>
+ </div>
+
+ <div class="test firstChild">
+ <div class="unitTest" title=":first-child selector"></div>
+ <div class="blox12 unitTest" title=":first-child selector should not match non first child"></div>
+ <div class="blox13 unitTest" title=":first-child selector should not match non first child"></div>
+ </div>
+
+ <div class="test not">
+ <div class="blox14 unitTest" title="negation pseudo-class with argument being an element type selector"></div>
+ <div class="blox15 unitTest" foo="blox15" title="negation pseudo-class with argument being an attribute selector"></div>
+ <div class="blox16 unitTest" foo="blox15" title="negation pseudo-class accepts only simple selectors for argument"></div>
+ </div>
+
+ <div class="test onlyOfType">
+ <div class="blox17 unitTest" title=":only-of-type selector"></div>
+ <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+ <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+ </div>
+
+ <div class="test nthchild1">
+ <div class="unitTest" title=":nth-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+ </div>
+ <div class="test nthchild2">
+ <div class="unitTest" title=":nth-last-child(even) selector"></div>
+ <div class="unitTest" title=":nth-child(even) selector"></div>
+ <div class="unitTest" title=":nth-last-child(even) selector"></div>
+ <div class="unitTest" title=":nth-child(even) selector"></div>
+ <div class="unitTest" title=":nth-last-child(even) selector"></div>
+ <div class="unitTest" title=":nth-child(even) selector"></div>
+ </div>
+ <div class="test nthchild3">
+ <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+ <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+ <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+ <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+ <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+ <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+ </div>
+
+ <div class="test nthoftype1">
+ <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+ </div>
+ <div class="test nthoftype2">
+ <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <div class="unitTest" title=":nth-of-type(even) selector"></div>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+ <div class="unitTest" title=":nth-of-type(even) selector"></div>
+ </div>
+ <div class="test nthoftype3">
+ <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+ <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+ <p class="unitTest" title=":nth-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+ <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+ </div>
+
+ <div class="test lastChild">
+ <p class="unitTest" title=":not(:last-child) selector"></p>
+ <div class="unitTest" title=":last-child selector"></div>&nbsp;
+ </div>
+
+ <div class="test firstOfType">
+ <p class="unitTest" title=":first-of-type selector"></p>
+ <div class="unitTest" title=":first-of-type selector"></div>
+ <p class="unitTest" title=":not(:first-of-type)"></p>
+ <div class="unitTest" title=":not(:first-of-type)"></div>
+ </div>
+
+ <div class="test lastOfType">
+ <p class="unitTest" title=":not(:last-of-type)"></p>
+ <div class="unitTest" title=":not(:last-of-type)"></div>
+ <p class="unitTest" title=":last-of-type selector"></p>
+ <div class="unitTest" title=":last-of-type selector"></div>
+ </div>
+
+ <div class="test onlyChild">
+ <div class="unitTest" title=":only-child where the element is NOT the only child"></div>
+ <div class="unitTest" title=":only-child where the element is the only child">
+ <div class="unitTest" title=":only-child where the element is the only child"></div>
+ </div>
+ </div>
+
+ <div class="test onlyOfType">
+ <p class="unitTest" title=":only-of-type"></p>
+ <div class="unitTest" title=":only-of-type">
+ <div class="unitTest" title=":only-of-type"></div>
+ </div>
+ <div class="unitTest" title=":not(only-of-type)"></div>
+ </div>
+
+ <div class="test empty">
+ <div class="unitTest isEmpty" title=":empty with empty element"></div>
+ <div class="unitTest isNotEmpty" title=":empty but element contains a whitespace"> </div>
+ <div class="unitTest isEmpty" title=":empty and element contains an SGML comment"><!-- foo --></div>
+ <div class="unitTest isNotEmpty" title=":empty but element contains a SPAN element"><span></span></div>
+ <div class="unitTest isNotEmpty" title=":empty but element contains an entity reference">&nbsp;</div>
+ </div>
+
+ <div class="test lang">
+ <div id="nofragment" class="unitTest" title=":lang() where language comes from the document"></div>
+ <div class="unitTest" lang="fr" title=":lang() where language comes from the element"></div>
+ <div class="unitTest" lang="en-US" title=":lang() where language comes from the element but is a dialect of the language queried"></div>
+ <div class="unitTest t1" lang="es" title=":lang() where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+ </div>
+
+ <div class="test attrLang">
+ <div class="unitTest t1" title="[|=] where language comes from the document"></div>
+ <div class="unitTest" lang="fr" title="[|=] where language comes from the element"></div>
+ <div class="unitTest t2" lang="en-US" title="[|=] where language comes from the element but is a dialect of the language queried"></div>
+ <div class="unitTest t3" lang="es" title="[|=] where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+ </div>
+
+ <div class="test UI">
+ <button name="submit" type="submit" value="submit" class="t1" title=":enabled pseudo-class"><div class="unitTest"></div></button>
+ <button name="submit" type="submit" value="submit" class="t2" disabled="true" title=":enabled pseudo-class"><div class="unitTest"></div></button>
+ </div>
+ <div class="test UI">
+ <input class="t3" type="checkbox" checked="true"/><div class="unitTest" title=":checked"></div>
+ the previous square should be green when the checkbox is checked and become red when you uncheck it
+ </div>
+ <div class="test UI">
+ <input class="t4" type="checkbox"/><div class="unitTest" title=":not(:checked)"></div>
+ the previous square should be green when the checkbox is NOT checked and become red when you check it
+ </div>
+
+ <div class="test tilda">
+ <div class="unitTest t1" title="~ combinator"></div>
+ <div class="unitTest" title="~ combinator"></div>
+ <div class="unitTest" title="~ combinator"></div>
+ <div class="unitTest" title="~ combinator"></div>
+ <span style="float:left">the three last squares should be green and become red when the pointer hovers over the white square</span>
+ </div>
+ <div class="test plus">
+ <div class="unitTest t1" title="+ combinator"></div>
+ <div class="unitTest t2" title="+ combinator"></div>
+ <div class="unitTest" title="+ combinator"></div>
+ <span style="float:left">the last square should be green and become red when the pointer hovers over the FIRST white square</span>
+ </div>
+</div>
+<div id="root2">
+ <div class="header">
+ <h3>CSS 3 Selectors tests</h3>
+ <p>(c) <a href="http://www.disruptive-innovations.com">Disruptive Innovations</a> 2008<br/>
+ Last update: 2008-06-06</p>
+ </div>
+
+ <div class="test">
+ <div class="blox1 unitTest" title="childhood selector"></div>
+ </div>
+
+ <div class="test attributeExistence">
+ <div class="blox2 unitTest" align="center" title="attribute existence selector"></div>
+ <div class="blox3 unitTest" align="" title="attribute existence selector with empty string value"></div>
+ <div class="blox4 unitTest" valign="center" title="attribute existence selector with almost identical attribute"></div>
+ <div class="blox5 unitTest" alignv="center" title="attribute existence selector with almost identical attribute"></div>
+ </div>
+
+ <div class="test attributeValue">
+ <div class="blox6 unitTest" align="center" title="attribute value selector"></div>
+ <div class="blox6 unitTest" foo="&eacute;" title="attribute value selector with an entity in the attribute and an escaped value in the selector"></div>
+ <div class="blox6 unitTest" _foo="&eacute;" title="attribute value selector with an entity in the attribute, an escaped value in the selector, and a leading underscore in the attribute name"></div>
+ </div>
+
+ <div class="test attributeSpaceSeparatedValues">
+ <div class="blox7 foo unitTest" title="[~=] attribute selector"></div>
+ <div class="blox8 unitTest" title="[~=] attribute selector looking for empty string"></div>
+ <div class="blox9 unitTest" foo="" title="[~=] attribute selector looking for empty string in empty attribute"></div>
+ <div class="blox10 unitTest" foo="foobar" title="[~=] attribute selector looking for 'foo' in 'foobar'"></div>
+ </div>
+
+ <div class="test attrStart">
+ <div class="unitTest t1" title="[^=] attribute selector"></div>
+ <div class="unitTest t2" title="[^=] attribute selector"></div>
+ <div class="unitTest t3" align="center" title="[^=] attribute selector looking for empty string"></div>
+ <div class="unitTest t4" foo="&eacute;tagada" title="[^=] attribute selector looking for &eacute;"></div>
+ </div>
+
+ <div class="test attrEnd">
+ <div class="unitTest t1" title="[$=] attribute selector"></div>
+ <div class="unitTest t2" title="[$=] attribute selector"></div>
+ <div class="unitTest t3" align="center" title="[$=] attribute selector looking for empty string"></div>
+ <div class="unitTest t4" foo="tagada&eacute;" title="[$=] attribute selector looking for &eacute;"></div>
+ </div>
+
+ <div class="test attrMiddle">
+ <div class="unitTest t1" title="[*=] attribute selector"></div>
+ <div class="unitTest t2" title="[*=] attribute selector"></div>
+ <div class="unitTest t3" align="center" title="[*=] attribute selector looking for empty string"></div>
+ <div class="unitTest t4" foo="tagada&eacute;foo" title="[*=] attribute selector looking for &eacute;"></div>
+ </div>
+
+ <div class="test firstChild">
+ <div class="unitTest" title=":first-child selector"></div>
+ <div class="blox12 unitTest" title=":first-child selector should not match non first child"></div>
+ <div class="blox13 unitTest" title=":first-child selector should not match non first child"></div>
+ </div>
+
+ <div class="test not">
+ <div class="blox14 unitTest" title="negation pseudo-class with argument being an element type selector"></div>
+ <div class="blox15 unitTest" foo="blox15" title="negation pseudo-class with argument being an attribute selector"></div>
+ <div class="blox16 unitTest" foo="blox15" title="negation pseudo-class accepts only simple selectors for argument"></div>
+ </div>
+
+ <div class="test onlyOfType">
+ <div class="blox17 unitTest" title=":only-of-type selector"></div>
+ <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+ <p class="blox18 unitTest" title="negated :only-of-type selector"></p>
+ </div>
+
+ <div class="test nthchild1">
+ <div class="unitTest" title=":nth-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-child(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-child(odd) selector"></div>
+ </div>
+ <div class="test nthchild2">
+ <div class="unitTest" title=":nth-last-child(even) selector"></div>
+ <div class="unitTest" title=":nth-child(even) selector"></div>
+ <div class="unitTest" title=":nth-last-child(even) selector"></div>
+ <div class="unitTest" title=":nth-child(even) selector"></div>
+ <div class="unitTest" title=":nth-last-child(even) selector"></div>
+ <div class="unitTest" title=":nth-child(even) selector"></div>
+ </div>
+ <div class="test nthchild3">
+ <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+ <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+ <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+ <div class="unitTest no" title=":nth-last-child(3n+3) selector"></div>
+ <div class="unitTest" title=":nth-child(3n+2) selector"></div>
+ <div class="unitTest no" title=":nth-last-child(3n+1) selector"></div>
+ </div>
+
+ <div class="test nthoftype1">
+ <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <div class="unitTest" title=":nth-of-type(odd) selector"></div>
+ <div class="unitTest" title=":nth-last-of-type(odd) selector"></div>
+ </div>
+ <div class="test nthoftype2">
+ <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <div class="unitTest" title=":nth-of-type(even) selector"></div>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(even) selector"></div>
+ <div class="unitTest" title=":nth-of-type(even) selector"></div>
+ </div>
+ <div class="test nthoftype3">
+ <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+ <div class="unitTest" title=":nth-of-type(3n+1) selector"></div>
+ <p class="unitTest" title=":nth-of-* selector"></p>
+ <div class="unitTest" title=":nth-last-of-type(3n+2) selector"></div>
+ <div class="unitTest" title=":nth-last-of-type(3n+1) selector"></div>
+ </div>
+
+ <div class="test lastChild">
+ <p class="unitTest" title=":not(:last-child) selector"></p>
+ <div class="unitTest" title=":last-child selector"></div>&nbsp;
+ </div>
+
+ <div class="test firstOfType">
+ <p class="unitTest" title=":first-of-type selector"></p>
+ <div class="unitTest" title=":first-of-type selector"></div>
+ <p class="unitTest" title=":not(:first-of-type)"></p>
+ <div class="unitTest" title=":not(:first-of-type)"></div>
+ </div>
+
+ <div class="test lastOfType">
+ <p class="unitTest" title=":not(:last-of-type)"></p>
+ <div class="unitTest" title=":not(:last-of-type)"></div>
+ <p class="unitTest" title=":last-of-type selector"></p>
+ <div class="unitTest" title=":last-of-type selector"></div>
+ </div>
+
+ <div class="test onlyChild">
+ <div class="unitTest" title=":only-child where the element is NOT the only child"></div>
+ <div class="unitTest" title=":only-child where the element is the only child">
+ <div class="unitTest" title=":only-child where the element is the only child"></div>
+ </div>
+ </div>
+
+ <div class="test onlyOfType">
+ <p class="unitTest" title=":only-of-type"></p>
+ <div class="unitTest" title=":only-of-type">
+ <div class="unitTest" title=":only-of-type"></div>
+ </div>
+ <div class="unitTest" title=":not(only-of-type)"></div>
+ </div>
+
+ <div class="test empty">
+ <div class="unitTest isEmpty" title=":empty with empty element"></div>
+ <div class="unitTest isNotEmpty" title=":empty but element contains a whitespace"> </div>
+ <div class="unitTest isEmpty" title=":empty and element contains an SGML comment"><!-- foo --></div>
+ <div class="unitTest isNotEmpty" title=":empty but element contains a SPAN element"><span></span></div>
+ <div class="unitTest isNotEmpty" title=":empty but element contains an entity reference">&nbsp;</div>
+ </div>
+
+ <div class="test lang">
+ <div id="nofragment" class="unitTest" title=":lang() where language comes from the document"></div>
+ <div class="unitTest" lang="fr" title=":lang() where language comes from the element"></div>
+ <div class="unitTest" lang="en-US" title=":lang() where language comes from the element but is a dialect of the language queried"></div>
+ <div class="unitTest t1" lang="es" title=":lang() where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+ </div>
+
+ <div class="test attrLang">
+ <div class="unitTest t1" title="[|=] where language comes from the document"></div>
+ <div class="unitTest" lang="fr" title="[|=] where language comes from the element"></div>
+ <div class="unitTest t2" lang="en-US" title="[|=] where language comes from the element but is a dialect of the language queried"></div>
+ <div class="unitTest t3" lang="es" title="[|=] where language comes from the element but the language queried is a dialect of the element's one so it should not match"></div>
+ </div>
+
+ <div class="test UI">
+ <button name="submit" type="submit" value="submit" class="t1" title=":enabled pseudo-class"><div class="unitTest"></div></button>
+ <button name="submit" type="submit" value="submit" class="t2" disabled="true" title=":enabled pseudo-class"><div class="unitTest"></div></button>
+ </div>
+ <div class="test UI">
+ <input class="t3" type="checkbox" checked="true"/><div class="unitTest" title=":checked"></div>
+ the previous square should be green when the checkbox is checked and become red when you uncheck it
+ </div>
+ <div class="test UI">
+ <input class="t4" type="checkbox"/><div class="unitTest" title=":not(:checked)"></div>
+ the previous square should be green when the checkbox is NOT checked and become red when you check it
+ </div>
+
+ <div class="test tilda">
+ <div class="unitTest t1" title="~ combinator"></div>
+ <div class="unitTest" title="~ combinator"></div>
+ <div class="unitTest" title="~ combinator"></div>
+ <div class="unitTest" title="~ combinator"></div>
+ <span style="float:left">the three last squares should be green and become red when the pointer hovers over the white square</span>
+ </div>
+ <div class="test plus">
+ <div class="unitTest t1" title="+ combinator"></div>
+ <div class="unitTest t2" title="+ combinator"></div>
+ <div class="unitTest" title="+ combinator"></div>
+ <span style="float:left">the last square should be green and become red when the pointer hovers over the FIRST white square</span>
+ </div>
+</div>
+<div id="root3">
+ <div id="svgs">
+ <!-- svg elements, but in the xhtml namespace -->
+ <svg width="12cm" height="4cm" viewBox="0 0 1200 400" version="1.1" id="svg1">
+ <desc id="desc1">Example circle01 - circle filled with red and stroked with blue</desc>
+ <rect id="rect1" x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/>
+ <circle id="circle1" cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10" />
+ </svg>
+ <!-- svg elements using svg: -->
+ <svg:svg width="12cm" height="4cm" viewBox="0 0 1200 400" version="1.1" id="svg2">
+ <svg:desc id="desc2">Example circle01 - circle filled with red and stroked with blue</svg:desc>
+ <svg:rect id="rect2" x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/>
+ <svg:circle id="circle2" cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10" />
+ </svg:svg>
+ <!-- svg using an inline xmlns -->
+ <svg width="12cm" height="4cm" viewBox="0 0 1200 400" xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg3">
+ <desc id="desc3">Example circle01 - circle filled with red and stroked with blue</desc>
+ <rect id="rect3" x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/>
+ <circle id="circle3" cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10" />
+ </svg>
+ </div>
+
+ <h1 id="header">jQuery Test Suite</h1>
+ <h2 id="banner"></h2>
+ <h2 id="userAgent"></h2>
+
+ <!-- Test HTML -->
+ <div id="nothiddendiv" style="height:1px;background:white;">
+
+ <div id="nothiddendivchild"></div>
+ </div>
+ <!-- Test for scoping -->
+ <nosuchtag id="outerbogustag">
+ <nosuchtag id="innerbogustag"></nosuchtag>
+ </nosuchtag>
+ <!-- this iframe is outside the #main so it won't reload constantly wasting time, but it means the tests must be "safe" and clean up after themselves -->
+ <iframe id="loadediframe" name="loadediframe" style="display:none;" src="data/iframe.html"></iframe>
+ <dl id="dl" style="display:none;">
+ <div id="main" style="display: none;">
+ <p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p>
+
+ <p id="ap">
+ Here are some links in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>,
+ <a id="groups" href="http://groups.google.com/">Google Groups</a>.
+ This link has <code><a href="http://smin" id="anchor1">class="blog"</a></code>:
+ <a href="http://diveintomark.org/" class="blog" hreflang="en" id="mark">diveintomark</a>
+
+ </p>
+ <div id="foo">
+
+ <p id="sndp">Everything inside the red border is inside a div with <code>id="foo"</code>.</p>
+ <p lang="en" id="en">This is a normal link: <a id="yahoo" href="http://www.yahoo.com/" class="blogTest">Yahoo</a></p>
+ <p id="sap">This link has <code><a href="#2" id="anchor2">class="blog"</a></code>: <a href="http://simon.incutio.com/" class="blog link" id="simon">Simon Willison's Weblog</a></p>
+
+ </div>
+
+ <p id="first">Try them out:</p>
+ <ul id="firstUL"></ul>
+ <ol id="empty"></ol>
+ <form id="form" action="formaction">
+ <input type="text" name="action" value="Test" id="text1" maxlength="30"/>
+ <input type="text" name="text2" value="Test" id="text2" disabled="disabled"/>
+ <input type="radio" name="radio1" id="radio1" value="on"/>
+
+ <input type="radio" name="radio2" id="radio2" checked="checked"/>
+
+ <input type="checkbox" name="check" id="check1" checked="checked"/>
+ <input type="checkbox" id="check2" value="on"/>
+
+ <input type="hidden" name="hidden" id="hidden1"/>
+ <input type="text" style="display:none;" name="foo[bar]" id="hidden2"/>
+
+ <input type="text" id="name" name="name" value="name" />
+
+ <button id="button" name="button">Button</button>
+
+ <textarea id="area1" maxlength="30">foobar</textarea>
+
+
+ <select name="select1" id="select1">
+ <option id="option1a" class="emptyopt" value="">Nothing</option>
+ <option id="option1b" value="1">1</option>
+ <option id="option1c" value="2">2</option>
+ <option id="option1d" value="3">3</option>
+ </select>
+ <select name="select2" id="select2">
+
+ <option id="option2a" class="emptyopt" value="">Nothing</option>
+ <option id="option2b" value="1">1</option>
+ <option id="option2c" value="2">2</option>
+ <option id="option2d" selected="selected" value="3">3</option>
+ </select>
+ <select name="select3" id="select3" multiple="multiple">
+ <option id="option3a" class="emptyopt" value="">Nothing</option>
+
+ <option id="option3b" selected="selected" value="1">1</option>
+ <option id="option3c" selected="selected" value="2">2</option>
+ <option id="option3d" value="3">3</option>
+ </select>
+
+ <object id="object1" codebase="stupid">
+ <param name="p1" value="x1" />
+ <param name="p2" value="x2" />
+
+ </object>
+
+ <span id="å°åŒ—TaÌibeÌŒi"></span>
+ <span id="å°åŒ—" lang="中文"></span>
+ <span id="utf8class1" class="å°åŒ—TaÌibeÌŒi å°åŒ—"></span>
+ <span id="utf8class2" class="å°åŒ—"></span>
+ <span id="foo:bar" class="foo:bar"></span>
+ <span id="test.foo[5]bar" class="test.foo[5]bar"></span>
+
+ <foo_bar id="foobar">test element</foo_bar>
+
+ </form>
+ <b id="floatTest">Float test.</b>
+ <iframe id="iframe" name="iframe"></iframe>
+ <form id="lengthtest">
+ <input type="text" id="length" name="test"/>
+ <input type="text" id="idTest" name="id"/>
+ </form>
+ <table id="table"></table>
+
+
+ <div id="fx-queue">
+ <div id="fadein" class='chain test'>fadeIn<div>fadeIn</div></div>
+ <div id="fadeout" class='chain test out'>fadeOut<div>fadeOut</div></div>
+
+ <div id="show" class='chain test'>show<div>show</div></div>
+ <div id="hide" class='chain test out'>hide<div>hide</div></div>
+
+
+ <div id="togglein" class='chain test'>togglein<div>togglein</div></div>
+ <div id="toggleout" class='chain test out'>toggleout<div>toggleout</div></div>
+
+
+ <div id="slideup" class='chain test'>slideUp<div>slideUp</div></div>
+ <div id="slidedown" class='chain test out'>slideDown<div>slideDown</div></div>
+
+ <div id="slidetogglein" class='chain test'>slideToggleIn<div>slideToggleIn</div></div>
+
+ <div id="slidetoggleout" class='chain test out'>slideToggleOut<div>slideToggleOut</div></div>
+ </div>
+
+ <div id="fx-tests"></div>
+
+ <form id="testForm" action="#" method="get">
+ <textarea name="T3" rows="2" cols="15">?
+Z</textarea>
+ <input type="hidden" name="H1" value="x" />
+ <input type="hidden" name="H2" />
+
+ <input name="PWD" type="password" value="" />
+ <input name="T1" type="text" />
+ <input name="T2" type="text" value="YES" readonly="readonly" />
+ <input type="checkbox" name="C1" value="1" />
+ <input type="checkbox" name="C2" />
+ <input type="radio" name="R1" value="1" />
+ <input type="radio" name="R1" value="2" />
+ <input type="text" name="My Name" value="me" />
+ <input type="reset" name="reset" value="NO" />
+
+ <select name="S1">
+ <option value="abc">ABC</option>
+ <option value="abc">ABC</option>
+ <option value="abc">ABC</option>
+ </select>
+ <select name="S2" multiple="multiple" size="3">
+ <option value="abc">ABC</option>
+
+ <option value="abc">ABC</option>
+ <option value="abc">ABC</option>
+ </select>
+ <select name="S3">
+ <option selected="selected">YES</option>
+ </select>
+ <select name="S4">
+
+ <option value="" selected="selected">NO</option>
+ </select>
+ <input type="submit" name="sub1" value="NO" />
+ <input type="submit" name="sub2" value="NO" />
+ <input type="image" name="sub3" value="NO" />
+ <button name="sub4" type="submit" value="NO">NO</button>
+ <input name="D1" type="text" value="NO" disabled="disabled" />
+ <input type="checkbox" checked="checked" disabled="disabled" name="D2" value="NO" />
+
+ <input type="radio" name="D3" value="NO" checked="checked" disabled="disabled" />
+ <select name="D4" disabled="disabled">
+ <option selected="selected" value="NO">NO</option>
+ </select>
+ </form>
+ <div id="moretests">
+ <form>
+ <div id="checkedtest" style="display:none;">
+
+ <input type="radio" name="checkedtestradios" checked="checked"/>
+ <input type="radio" name="checkedtestradios" value="on"/>
+ <input type="checkbox" name="checkedtestcheckboxes" checked="checked"/>
+ <input type="checkbox" name="checkedtestcheckboxes" />
+ </div>
+ </form>
+ <div id="nonnodes"><span>hi</span> there <!-- mon ami --></div>
+
+ <div id="t2037">
+ <div><div class="hidden">hidden</div></div>
+ </div>
+ </div>
+ </div>
+ </dl>
+
+ <ol id="tests"></ol>
+</div>
+<ol id="results"></ol>
+</body>
+</html>
diff --git a/dom/base/test/file_bug426646-1.html b/dom/base/test/file_bug426646-1.html
new file mode 100644
index 0000000000..4319311b08
--- /dev/null
+++ b/dom/base/test/file_bug426646-1.html
@@ -0,0 +1,37 @@
+<html><head>
+<title>Bug 426646, Using location.replace breaks iframe history</title>
+<script type="text/javascript">
+var BASE_URI = "http://mochi.test:8888/tests/dom/base/test/";
+var url1 = BASE_URI + "iframe1_bug426646.html";
+
+function soon(f) {
+ return function() { setTimeout(f, 0); };
+}
+
+function doe() {
+ document.body.innerHTML = "<iframe src='about:blank'></iframe>";
+ document.body.innerHTML += "<iframe src='about:blank'></iframe>";
+ window.frames[0].frameElement.onload = soon(doe2);
+ window.frames[0].location.replace(url1);
+}
+
+function doe2() {
+ window.frames[0].location = 'iframe2_bug426646.html';
+ window.frames[0].frameElement.onload = soon(doe3);
+}
+
+function doe3() {
+ window.frames[0].frameElement.onload = soon(doe4);
+ history.go(-1);
+}
+
+function doe4() {
+ opener.is(String(window.frames[0].location), url1, "History.go(-1) didn't work?");
+ opener.is(String(window.frames[1].location), "about:blank",
+ "History.go(-1) didn't work?");
+ close();
+}
+</script>
+</head>
+<body onload="doe();" onunload="opener.nextTest();">
+</body></html>
diff --git a/dom/base/test/file_bug426646-2.html b/dom/base/test/file_bug426646-2.html
new file mode 100644
index 0000000000..2da090b32f
--- /dev/null
+++ b/dom/base/test/file_bug426646-2.html
@@ -0,0 +1,65 @@
+<html><head>
+<title>Bug 426646, Using location.replace breaks iframe history</title>
+<script type="text/javascript">
+var BASE_URI = "http://mochi.test:8888/tests/dom/base/test/";
+var url1 = BASE_URI + "iframe1_bug426646.html";
+
+var win0 = null;
+
+function soon(f) {
+ return function() { setTimeout(f, 0); };
+}
+
+function doe() {
+ document.body.innerHTML = "<iframe src='about:blank'></iframe>";
+ document.body.innerHTML += "<iframe src='about:blank'></iframe>";
+ win0 = window.frames[0];
+ win0.frameElement.onload = soon(doe2);
+ win0.location.replace(url1);
+}
+
+function doe2() {
+ // Add some iframes/docshells. Session history should still work.
+ var ifr1 = document.createElement("iframe");
+ document.body.insertBefore(ifr1, document.body.firstChild);
+ ifr1.onload = soon(doe3);
+
+ var ifr2 = document.createElement("iframe");
+ document.body.insertBefore(ifr2, document.body.firstChild);
+ ifr2.onload = soon(doe3);
+
+ var ifr3 = document.createElement("iframe");
+ document.body.insertBefore(ifr3, document.body.firstChild);
+ ifr3.onload = soon(doe3);
+}
+
+var doe3_count = 0;
+function doe3() {
+ // Wait until all three iframes have loaded about:blank before navigating
+ // win0.
+ doe3_count++;
+ if (doe3_count < 3) {
+ return;
+ }
+ if (doe3_count > 3) {
+ ok(false, 'Unexpected ' + doe3_count + 'th call to doe3.');
+ return;
+ }
+
+ win0.frameElement.onload = soon(doe4);
+ win0.location = BASE_URI + 'iframe2_bug426646.html';
+}
+
+function doe4() {
+ win0.frameElement.onload = soon(doe5);
+ history.go(-1);
+}
+
+function doe5() {
+ opener.is(String(win0.location), url1, "History.go(-1) didn't work?");
+ close();
+}
+</script>
+</head>
+<body onload="setTimeout(doe, 0);" onunload="opener.nextTest();">
+</body></html>
diff --git a/dom/base/test/file_bug428847-1.xhtml b/dom/base/test/file_bug428847-1.xhtml
new file mode 100644
index 0000000000..b88701ece2
--- /dev/null
+++ b/dom/base/test/file_bug428847-1.xhtml
@@ -0,0 +1,4 @@
+<?xml-stylesheet type="text/xsl" href="http://example.com/whatever.xsl"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body id='body' onload="if (document.getElementById('body')) parent.iframe1Loaded = true;"/>
+</html>
diff --git a/dom/base/test/file_bug428847-2.xhtml b/dom/base/test/file_bug428847-2.xhtml
new file mode 100644
index 0000000000..75c60b7792
--- /dev/null
+++ b/dom/base/test/file_bug428847-2.xhtml
@@ -0,0 +1,4 @@
+<?xml-stylesheet type="text/xsl" href=":"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body id='body' onload="if (document.getElementById('body')) parent.iframeLoaded = true;"/>
+</html>
diff --git a/dom/base/test/file_bug498897.css b/dom/base/test/file_bug498897.css
new file mode 100644
index 0000000000..84beffdefc
--- /dev/null
+++ b/dom/base/test/file_bug498897.css
@@ -0,0 +1 @@
+body { background: orange; }
diff --git a/dom/base/test/file_bug498897.html b/dom/base/test/file_bug498897.html
new file mode 100644
index 0000000000..b0d36f4ca5
--- /dev/null
+++ b/dom/base/test/file_bug498897.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+ <title>Testcase for bug 498897</title>
+<script type="application/javascript" language="javascript">
+<!--
+function test()
+{
+ var hadException = false;
+ try {
+ document.createComment('a');
+ }
+ catch (e) {
+ hadException = true;
+ }
+ parent.ok(!hadException, "Shouldn't have got an exception!");
+ parent.testFinished();
+}
+//-->
+</script>
+</head>
+<body onload="test();">
+</body>
+</html>
diff --git a/dom/base/test/file_bug498897.html^headers^ b/dom/base/test/file_bug498897.html^headers^
new file mode 100644
index 0000000000..09b46ca4ee
--- /dev/null
+++ b/dom/base/test/file_bug498897.html^headers^
@@ -0,0 +1 @@
+Link: <file_bug498897.css>; rel=stylesheet
diff --git a/dom/base/test/file_bug503473-frame.sjs b/dom/base/test/file_bug503473-frame.sjs
new file mode 100644
index 0000000000..f642241091
--- /dev/null
+++ b/dom/base/test/file_bug503473-frame.sjs
@@ -0,0 +1,22 @@
+function handleRequest(request, response) {
+ response.processAsync();
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ response.write(
+ "<!DOCTYPE html>" +
+ "<div></div>" +
+ "<script>" +
+ "function doWrite() {" +
+ ' document.write("<p></p>");' +
+ " parent.done();" +
+ " document.close();" +
+ "}" +
+ "setTimeout(doWrite, 0);" +
+ "</script>"
+ );
+
+ response.bodyOutputStream.flush();
+ // leave the stream open
+}
diff --git a/dom/base/test/file_bug503481.sjs b/dom/base/test/file_bug503481.sjs
new file mode 100644
index 0000000000..9aaeb31744
--- /dev/null
+++ b/dom/base/test/file_bug503481.sjs
@@ -0,0 +1,54 @@
+// 'timer' is global to avoid getting GCed which would cancel the timer
+var timer;
+const nsITimer = Components.interfaces.nsITimer;
+
+function attemptUnblock(s) {
+ try {
+ let blockedResponse = null;
+ getObjectState("bug503481_" + s, function (x) {
+ blockedResponse = x.wrappedJSObject.r;
+ });
+ blockedResponse.finish();
+ setObjectState("bug503481_" + s, null);
+ } catch (e) {
+ dump("unable to unblock " + s + "retrying in half a second\n");
+ timer = Components.classes["@mozilla.org/timer;1"].createInstance(nsITimer);
+ timer.initWithCallback(
+ function () {
+ attemptUnblock(s);
+ },
+ 500,
+ nsITimer.TYPE_ONE_SHOT
+ );
+ }
+}
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ dump("processing:" + request.queryString + "\n");
+
+ if (query.unblock) {
+ attemptUnblock(query.unblock);
+ }
+
+ if (query.blockOn) {
+ response.processAsync();
+ x = {
+ r: response,
+ QueryInterface(iid) {
+ return this;
+ },
+ };
+ x.wrappedJSObject = x;
+ setObjectState("bug503481_" + query.blockOn, x);
+ }
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(query.body);
+}
diff --git a/dom/base/test/file_bug503481b_inner.html b/dom/base/test/file_bug503481b_inner.html
new file mode 100644
index 0000000000..6b34bc47b6
--- /dev/null
+++ b/dom/base/test/file_bug503481b_inner.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<!-- Async script that isn't preloaded -->
+<script async src="file_bug503481.sjs?blockOn=R&body=runFirst();"></script>
+<script>
+firstRan = false;
+secondRan = false;
+thirdRan = false;
+forthRan = false;
+function runFirst() {
+ firstRan = true;
+}
+function runThird() {
+ parent.is(forthRan, false, "forth should still be blocked");
+ unblock("T");
+ thirdRan = true;
+}
+function runForth() {
+ forthRan = true;
+}
+
+function done() {
+ parent.is(firstRan, true, "first should have run by onload");
+ parent.is(secondRan, true, "second should have run by onload");
+ parent.is(thirdRan, true, "third should have run by onload");
+ parent.is(forthRan, true, "forth should have run by onload");
+ parent.SimpleTest.finish();
+}
+
+var reqs = [];
+function unblock(s) {
+ xhr = new XMLHttpRequest();
+ xhr.open("GET", "file_bug503481.sjs?unblock=" + s);
+ xhr.send();
+ reqs.push(xhr);
+}
+
+
+parent.is(firstRan, false, "First async script shouldn't have run");
+unblock("R");
+</script>
+
+<!-- test that inline async isn't actually async -->
+<script async>
+secondRan = true;
+</script>
+<script>
+parent.is(secondRan, true, "Second script shouldn't be async");
+</script>
+
+<!-- test that setting both defer and async treats the script as async -->
+<script defer async src="file_bug503481.sjs?blockOn=S&body=runThird();"></script>
+<script>
+parent.is(thirdRan, false, "third should not have run yet");
+unblock("S");
+</script>
+<script src="file_bug503481.sjs?blockOn=T&body=runForth();"></script>
+
+</head>
+
+<body onload="done()">
diff --git a/dom/base/test/file_bug518104.js b/dom/base/test/file_bug518104.js
new file mode 100644
index 0000000000..72a684522f
--- /dev/null
+++ b/dom/base/test/file_bug518104.js
@@ -0,0 +1,3 @@
+document.write("<p></p>");
+parent.done();
+document.close();
diff --git a/dom/base/test/file_bug541937.html b/dom/base/test/file_bug541937.html
new file mode 100644
index 0000000000..93056754f9
--- /dev/null
+++ b/dom/base/test/file_bug541937.html
@@ -0,0 +1,7 @@
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test</title>
+ <link rel="Top" href=""> foo </link>
+
+</head><body>
+ <p>Hello world</p>
+</body></html> \ No newline at end of file
diff --git a/dom/base/test/file_bug541937.xhtml b/dom/base/test/file_bug541937.xhtml
new file mode 100644
index 0000000000..f4e5f3d320
--- /dev/null
+++ b/dom/base/test/file_bug541937.xhtml
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test</title>
+ <link rel="Top" href=""> foo </link>
+
+</head>
+<body>
+ <p>Hello world</p>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_bug557892.html b/dom/base/test/file_bug557892.html
new file mode 100644
index 0000000000..4b91ddafdd
--- /dev/null
+++ b/dom/base/test/file_bug557892.html
@@ -0,0 +1,25 @@
+<html><head>
+<title>Crash [@ nsGenericElement::SetAttr] with classList.toggle</title>
+<script>
+var classList;
+var interval;
+function run() {
+ classList = window.frames[0].document.documentElement.classList;
+ window.frames[0].location.reload();
+ interval = setInterval(function(aClassList) {aClassList.toggle('a'); forcegc();}, 10, classList);
+ // Let the interval run for awhile and close the window after 2 seconds.
+ setTimeout(function() { clearInterval(interval); window.opener.done(); window.close(); }, 2000);
+}
+
+function forcegc(){
+ SpecialPowers.forceGC();
+ SpecialPowers.gc();
+}
+
+ </script>
+ </head>
+ <body onload="run()">
+ <iframe></iframe>
+ </body>
+</html>
+
diff --git a/dom/base/test/file_bug562137.txt b/dom/base/test/file_bug562137.txt
new file mode 100644
index 0000000000..4a21b817e5
--- /dev/null
+++ b/dom/base/test/file_bug562137.txt
@@ -0,0 +1 @@
+I have nbsp
diff --git a/dom/base/test/file_bug590812-ref.xhtml b/dom/base/test/file_bug590812-ref.xhtml
new file mode 100644
index 0000000000..7309425fb4
--- /dev/null
+++ b/dom/base/test/file_bug590812-ref.xhtml
@@ -0,0 +1,3 @@
+<out><div id="top" xmlns="http://www.w3.org/1999/xhtml"><link href="chrome://global/content/xml/XMLPrettyPrint.css" type="text/css" rel="stylesheet"/><div id="header"><p>
+ This XML file does not appear to have any style information associated with it. The document tree is shown below.
+ </p></div><main id="tree" class="highlight"><div>&lt;<span class="start-tag">out</span>&gt;<span class="text">Here be sea hags</span>&lt;/<span class="end-tag">out</span>&gt;</div></main></div></out>
diff --git a/dom/base/test/file_bug590812.xml b/dom/base/test/file_bug590812.xml
new file mode 100644
index 0000000000..759d5066cf
--- /dev/null
+++ b/dom/base/test/file_bug590812.xml
@@ -0,0 +1 @@
+<out>Here be sea hags</out>
diff --git a/dom/base/test/file_bug590870.html b/dom/base/test/file_bug590870.html
new file mode 100644
index 0000000000..4432b01d3c
--- /dev/null
+++ b/dom/base/test/file_bug590870.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <script>
+onload = function() {
+ var x = null;
+ try {
+ x = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "spacer");
+ } catch(ex) {}
+ window.parent.postMessage(x == null, "http://mochi.test:8888");
+}
+ </script>
+ </head>
+ <body>
+ Here be dragons!
+ </body>
+</html>
diff --git a/dom/base/test/file_bug601803a.html b/dom/base/test/file_bug601803a.html
new file mode 100644
index 0000000000..c39ff7219e
--- /dev/null
+++ b/dom/base/test/file_bug601803a.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 601803</title>
+<script type="application/javascript">
+function runTest() {
+ document.domain = "example.org";
+ var thrown = false;
+ try {
+ document.getElementById("frame").contentDocument.adoptNode(document.createTextNode("foo"));
+ }
+ catch (e) {
+ thrown = true;
+ }
+ parent.postMessage(thrown, "*");
+}
+</script>
+</head>
+<body>
+<iframe id="frame" src="http://test1.example.org/tests/dom/base/test/file_bug601803b.html" onload="runTest();"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_bug601803b.html b/dom/base/test/file_bug601803b.html
new file mode 100644
index 0000000000..0363654c06
--- /dev/null
+++ b/dom/base/test/file_bug601803b.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 601803</title>
+</head>
+<body>
+<script type="application/javascript">
+document.domain = "example.org";
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_bug604660-1.xml b/dom/base/test/file_bug604660-1.xml
new file mode 100644
index 0000000000..231b4357d6
--- /dev/null
+++ b/dom/base/test/file_bug604660-1.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="file_bug604660-2.xsl" ?>
+<placeholder/>
diff --git a/dom/base/test/file_bug604660-2.xsl b/dom/base/test/file_bug604660-2.xsl
new file mode 100644
index 0000000000..16611726ce
--- /dev/null
+++ b/dom/base/test/file_bug604660-2.xsl
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:template match="/">
+ <html>
+ <head>
+ <title>XSLT script execution test</title>
+ </head>
+ <body>
+ <script defer="" src="data:text/javascript,parent.scriptRan(5);"></script>
+ <script>parent.scriptRan(1);</script>
+ <script async="" src="data:text/javascript,parent.asyncRan();"></script>
+ <script src="file_bug604660-3.js"></script>
+ <script>parent.scriptRan(3);</script>
+ <script src="file_bug604660-4.js"></script>
+ </body>
+ </html>
+ </xsl:template>
+</xsl:stylesheet>
+
diff --git a/dom/base/test/file_bug604660-3.js b/dom/base/test/file_bug604660-3.js
new file mode 100644
index 0000000000..c11ae68f28
--- /dev/null
+++ b/dom/base/test/file_bug604660-3.js
@@ -0,0 +1 @@
+parent.scriptRan(2);
diff --git a/dom/base/test/file_bug604660-4.js b/dom/base/test/file_bug604660-4.js
new file mode 100644
index 0000000000..2bd5b43e5b
--- /dev/null
+++ b/dom/base/test/file_bug604660-4.js
@@ -0,0 +1 @@
+parent.scriptRan(4);
diff --git a/dom/base/test/file_bug604660-5.xml b/dom/base/test/file_bug604660-5.xml
new file mode 100644
index 0000000000..58c6382836
--- /dev/null
+++ b/dom/base/test/file_bug604660-5.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<placeholder/>
diff --git a/dom/base/test/file_bug604660-6.xsl b/dom/base/test/file_bug604660-6.xsl
new file mode 100644
index 0000000000..4a75777d90
--- /dev/null
+++ b/dom/base/test/file_bug604660-6.xsl
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
+ <xsl:template match="/">
+ <html>
+ <script>xsltProcessorCreatedScriptRan();</script>
+ </html>
+ </xsl:template>
+</xsl:stylesheet>
+
diff --git a/dom/base/test/file_bug622088.sjs b/dom/base/test/file_bug622088.sjs
new file mode 100644
index 0000000000..87acdc3b8b
--- /dev/null
+++ b/dom/base/test/file_bug622088.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response) {
+ // Echos the referrer back to the requester.
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(request.getHeader("Referer"));
+}
diff --git a/dom/base/test/file_bug622088_inner.html b/dom/base/test/file_bug622088_inner.html
new file mode 100644
index 0000000000..e89273d89b
--- /dev/null
+++ b/dom/base/test/file_bug622088_inner.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script>
+function load() {
+ (window.opener || window.parent).innerLoaded(window);
+}
+
+function doXHR(req) {
+ // Do a sync XHR and return the XHR's referrer.
+ if (!req) {
+ req = new XMLHttpRequest();
+ }
+
+ // file_bug622088.sjs echos its referrer back to us. We need to refer to it
+ // using an absolute URI because we sometimes pass in |req| from a window
+ // which has a data: URI. In that case, a relative path would not get
+ // resolved properly!
+ //
+ // Resolve our relative URI to an absolute one by creating an anchor element
+ // and reading its href property.
+ var anchor = document.createElement('a');
+ anchor.href = 'file_bug622088.sjs';
+
+ dump('anchor.href=' + anchor.href + '\n');
+
+ req.open('GET', anchor.href, false);
+ req.send(null);
+ return req.responseText;
+}
+</script>
+</head>
+
+<body onload='load()'>
+<!--Inner frame target for test_bug622088_2.html. -->
+</body>
+
+</html>
diff --git a/dom/base/test/file_bug675121.sjs b/dom/base/test/file_bug675121.sjs
new file mode 100644
index 0000000000..29fef155df
--- /dev/null
+++ b/dom/base/test/file_bug675121.sjs
@@ -0,0 +1,19 @@
+var timer;
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write("Responded");
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"].createInstance(
+ Components.interfaces.nsITimer
+ );
+ timer.initWithCallback(
+ function () {
+ response.finish();
+ // 50ms certainly be enough for one refresh driver firing to happen!
+ },
+ 50,
+ Components.interfaces.nsITimer.TYPE_ONE_SHOT
+ );
+}
diff --git a/dom/base/test/file_bug687859-16.js b/dom/base/test/file_bug687859-16.js
new file mode 100644
index 0000000000..58f82cdda3
--- /dev/null
+++ b/dom/base/test/file_bug687859-16.js
Binary files differ
diff --git a/dom/base/test/file_bug687859-16.js^headers^ b/dom/base/test/file_bug687859-16.js^headers^
new file mode 100644
index 0000000000..e0d4fce5d0
--- /dev/null
+++ b/dom/base/test/file_bug687859-16.js^headers^
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=tis-620
diff --git a/dom/base/test/file_bug687859-bom.js b/dom/base/test/file_bug687859-bom.js
new file mode 100644
index 0000000000..7536004bb6
--- /dev/null
+++ b/dom/base/test/file_bug687859-bom.js
@@ -0,0 +1 @@
+var stringFromBomScript = "€";
diff --git a/dom/base/test/file_bug687859-bom.js^headers^ b/dom/base/test/file_bug687859-bom.js^headers^
new file mode 100644
index 0000000000..e0d4fce5d0
--- /dev/null
+++ b/dom/base/test/file_bug687859-bom.js^headers^
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=tis-620
diff --git a/dom/base/test/file_bug687859-charset.js b/dom/base/test/file_bug687859-charset.js
new file mode 100644
index 0000000000..e812a1e37f
--- /dev/null
+++ b/dom/base/test/file_bug687859-charset.js
@@ -0,0 +1 @@
+var stringFromCharsetScript = "¡"; \ No newline at end of file
diff --git a/dom/base/test/file_bug687859-http.js b/dom/base/test/file_bug687859-http.js
new file mode 100644
index 0000000000..1b1456d480
--- /dev/null
+++ b/dom/base/test/file_bug687859-http.js
@@ -0,0 +1 @@
+var stringFromHttpScript = "ä";
diff --git a/dom/base/test/file_bug687859-http.js^headers^ b/dom/base/test/file_bug687859-http.js^headers^
new file mode 100644
index 0000000000..e0d4fce5d0
--- /dev/null
+++ b/dom/base/test/file_bug687859-http.js^headers^
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=tis-620
diff --git a/dom/base/test/file_bug687859-inherit.js b/dom/base/test/file_bug687859-inherit.js
new file mode 100644
index 0000000000..b83f60b2fb
--- /dev/null
+++ b/dom/base/test/file_bug687859-inherit.js
@@ -0,0 +1 @@
+var stringFromInheritScript = "¡"; \ No newline at end of file
diff --git a/dom/base/test/file_bug692434.xml b/dom/base/test/file_bug692434.xml
new file mode 100644
index 0000000000..2d559c3aed
--- /dev/null
+++ b/dom/base/test/file_bug692434.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="windows-1251"?><root>Þ</root>
diff --git a/dom/base/test/file_bug704320_preload_attr.html b/dom/base/test/file_bug704320_preload_attr.html
new file mode 100644
index 0000000000..e10f1727df
--- /dev/null
+++ b/dom/base/test/file_bug704320_preload_attr.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test whether the speculative parser should use the referrerpolicy attribute
+https://bugzilla.mozilla.org/show_bug.cgi?id=1399780
+-->
+<head>
+ <meta charset="utf-8">
+ <script type="text/javascript" src="file_bug704320_preload_common.js"></script>
+ <script language="javascript" type="text/javascript">
+ // interfere doc.write(meta referrer) to the down side preloads
+ document.write("<meta name='referrer' content='unsafe-url'>");
+ </script>
+
+ <link rel="stylesheet"
+ href="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=css"
+ onload="incrementLoad2('link', 3);"
+ referrerpolicy="origin"/>
+
+ <img src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=img"
+ onload="incrementLoad2('img', 3);"
+ referrerpolicy="origin"/>
+
+ <script src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=js"
+ onload="incrementLoad2('script', 3);"
+ referrerpolicy="origin"></script>
+
+
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/base/test/file_bug704320_preload_common.js b/dom/base/test/file_bug704320_preload_common.js
new file mode 100644
index 0000000000..c7a409e297
--- /dev/null
+++ b/dom/base/test/file_bug704320_preload_common.js
@@ -0,0 +1,32 @@
+// Common code for the iframes used by bug704320_preload.
+
+var loadCount = 0;
+
+// Called by the various onload handlers to indicate that a resource has
+// been fully loaded. We require three loads to complete (img, script,
+// link) for this test.
+function incrementLoad(tag) {
+ loadCount++;
+ if (loadCount == 3) {
+ window.parent.postMessage("childLoadComplete", window.location.origin);
+ } else if (loadCount > 3) {
+ document.write("<h1>Too Many Load Events!</h1>");
+ window.parent.postMessage("childOverload", window.location.origin);
+ }
+}
+
+// This is same as incrementLoad, but the caller passes in the loadCount.
+function incrementLoad2(tag, expectedLoadCount) {
+ loadCount++;
+ if (loadCount == expectedLoadCount) {
+ window.parent.postMessage("childLoadComplete", window.location.origin);
+ } else if (loadCount > expectedLoadCount) {
+ document.write("<h1>Too Many Load Events!</h1>");
+ window.parent.postMessage("childOverload", window.location.origin);
+ }
+}
+
+// in case something fails to load, cause the test to fail.
+function postfail(msg) {
+ window.parent.postMessage("fail-" + msg, window.location.origin);
+}
diff --git a/dom/base/test/file_bug704320_preload_reuse.html b/dom/base/test/file_bug704320_preload_reuse.html
new file mode 100644
index 0000000000..5643e3d8d6
--- /dev/null
+++ b/dom/base/test/file_bug704320_preload_reuse.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This is a spot check for whether the speculative parser reuses style, script or image loads after the referrer policy has changed.
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+-->
+<head>
+ <meta charset="utf-8">
+ <meta name="referrer" content="origin">
+ <script type="text/javascript" src="file_bug704320_preload_common.js"></script>
+ <script language="javascript" type="text/javascript">
+ // mess with parser speculation -- the loads here MAY be reused because the
+ // referrer policy did not change.
+ document.write("<meta name='referrer' content='origin'>");
+ </script>
+
+ <script src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=js"
+ onload="incrementLoad('script');"></script>
+
+ <link rel="stylesheet"
+ href="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=css"
+ onload="incrementLoad('link');"/>
+
+</head>
+<body>
+
+<img src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=img"
+ onload="incrementLoad('img');"
+ onerror="postfail('image load caused an error in reuse test');"/>
+</body>
+</html>
diff --git a/dom/base/test/file_bug704320_redirect.html b/dom/base/test/file_bug704320_redirect.html
new file mode 100644
index 0000000000..09ed05d6fd
--- /dev/null
+++ b/dom/base/test/file_bug704320_redirect.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ parent.postMessage('', 'http://mochi.test:8888');
+ </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/base/test/file_bug707142_baseline.json b/dom/base/test/file_bug707142_baseline.json
new file mode 100644
index 0000000000..8c850a5fd2
--- /dev/null
+++ b/dom/base/test/file_bug707142_baseline.json
@@ -0,0 +1 @@
+{ "foo": "bar" }
diff --git a/dom/base/test/file_bug707142_bom.json b/dom/base/test/file_bug707142_bom.json
new file mode 100644
index 0000000000..e961357349
--- /dev/null
+++ b/dom/base/test/file_bug707142_bom.json
@@ -0,0 +1 @@
+{ "foo": "bar" }
diff --git a/dom/base/test/file_bug707142_utf-16.json b/dom/base/test/file_bug707142_utf-16.json
new file mode 100644
index 0000000000..eb28f6bb7e
--- /dev/null
+++ b/dom/base/test/file_bug707142_utf-16.json
Binary files differ
diff --git a/dom/base/test/file_bug708620-2.html b/dom/base/test/file_bug708620-2.html
new file mode 100644
index 0000000000..86899201df
--- /dev/null
+++ b/dom/base/test/file_bug708620-2.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Non-UTF form target</title>
+<body onload="parent.finish();">
diff --git a/dom/base/test/file_bug708620.html b/dom/base/test/file_bug708620.html
new file mode 100644
index 0000000000..a90e6aeeba
--- /dev/null
+++ b/dom/base/test/file_bug708620.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=windows-1252>
+<title>Non-UTF form</title>
+<body onload="document.forms[0].submit();">
+<form action="file_bug708620-2.html">
+<input name=foo value=bar>
+</form>
diff --git a/dom/base/test/file_bug753278.html b/dom/base/test/file_bug753278.html
new file mode 100644
index 0000000000..922bc0c658
--- /dev/null
+++ b/dom/base/test/file_bug753278.html
@@ -0,0 +1 @@
+<meta charset="utf-8"><script>parent.pass();</script>
diff --git a/dom/base/test/file_bug769117.html b/dom/base/test/file_bug769117.html
new file mode 100644
index 0000000000..424f8dff1c
--- /dev/null
+++ b/dom/base/test/file_bug769117.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=769117
+ -->
+ <head>
+ </head>
+ <body>
+ <embed id="testembed"
+ src="https://mochitest.youtube.com/v/Xm5i5kbIXzc"
+ type="application/x-shockwave-flash"
+ allowscriptaccess="always"></embed>
+ <object id="testobject"
+ data="https://mochitest.youtube.com/v/Xm5i5kbIXzc"></embed>
+ </body>
+</html>
diff --git a/dom/base/test/file_bug782342.txt b/dom/base/test/file_bug782342.txt
new file mode 100644
index 0000000000..3b18e512db
--- /dev/null
+++ b/dom/base/test/file_bug782342.txt
@@ -0,0 +1 @@
+hello world
diff --git a/dom/base/test/file_bug787778.sjs b/dom/base/test/file_bug787778.sjs
new file mode 100644
index 0000000000..d22d67d9c9
--- /dev/null
+++ b/dom/base/test/file_bug787778.sjs
@@ -0,0 +1,7 @@
+function handleRequest(request, response) {
+ response.processAsync();
+ response.setHeader("Content-Type", "text/plain", false);
+ response.setHeader("X-Frame-Options", "DENY", false);
+
+ response.finish();
+}
diff --git a/dom/base/test/file_bug869432.eventsource b/dom/base/test/file_bug869432.eventsource
new file mode 100644
index 0000000000..de92d4dd86
--- /dev/null
+++ b/dom/base/test/file_bug869432.eventsource
@@ -0,0 +1,4 @@
+retry:500
+data: data
+
+
diff --git a/dom/base/test/file_bug869432.eventsource^headers^ b/dom/base/test/file_bug869432.eventsource^headers^
new file mode 100644
index 0000000000..b8db77c582
--- /dev/null
+++ b/dom/base/test/file_bug869432.eventsource^headers^
@@ -0,0 +1,3 @@
+HTTP 304 NO CONTENT (CLOSE)
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate \ No newline at end of file
diff --git a/dom/base/test/file_bug902350.html b/dom/base/test/file_bug902350.html
new file mode 100644
index 0000000000..2101f80c7d
--- /dev/null
+++ b/dom/base/test/file_bug902350.html
@@ -0,0 +1,19 @@
+<DOCTYPE HTML>
+<html>
+<!--
+Test for Mixed Content Blocker target="_top" frame navigation
+https://bugzilla.mozilla.org/show_bug.cgi?id=902350
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 902350</title>
+</head>
+
+<body>
+ <div id="framediv">
+ <iframe src="https://example.com/browser/dom/base/test/file_bug902350_frame.html" id="testing_frame"></iframe>
+ </div>
+</body>
+</html>
+
+
diff --git a/dom/base/test/file_bug902350_frame.html b/dom/base/test/file_bug902350_frame.html
new file mode 100644
index 0000000000..183dabe255
--- /dev/null
+++ b/dom/base/test/file_bug902350_frame.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Tests for Mixed Content Blocker - Opening link with _top target from an https iframe.
+https://bugzilla.mozilla.org/show_bug.cgi?id=902350
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tests for Mixed Content Frame Navigation</title>
+</head>
+<body>
+<a href="http://example.com/" id="topTarget" target="_top">Go to http site</a>
+</body>
+</html>
diff --git a/dom/base/test/file_bug907892.html b/dom/base/test/file_bug907892.html
new file mode 100644
index 0000000000..9f5948661c
--- /dev/null
+++ b/dom/base/test/file_bug907892.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script>
+ var threw;
+ try {
+ document.domain = "example.org";
+ threw = false;
+ } catch (e) {
+ threw = true;
+ }
+ var sandboxed = (location.search == "?sandboxed");
+ parent.postMessage({ threw, sandboxed }, "*");
+</script>
diff --git a/dom/base/test/file_bug945152.jar b/dom/base/test/file_bug945152.jar
new file mode 100644
index 0000000000..eb732980d9
--- /dev/null
+++ b/dom/base/test/file_bug945152.jar
Binary files differ
diff --git a/dom/base/test/file_bug945152_worker.js b/dom/base/test/file_bug945152_worker.js
new file mode 100644
index 0000000000..9664045b6d
--- /dev/null
+++ b/dom/base/test/file_bug945152_worker.js
@@ -0,0 +1,99 @@
+var gData1 = "TEST_DATA_1:ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+var gData2 = "TEST_DATA_2:1234567890";
+var gPaddingChar = ".";
+var gPaddingSize = 10000;
+var gPadding = "";
+
+for (var i = 0; i < gPaddingSize; i++) {
+ gPadding += gPaddingChar;
+}
+
+function ok(a, msg) {
+ postMessage({ type: "status", status: !!a, msg });
+}
+
+function is(a, b, msg) {
+ postMessage({ type: "status", status: a === b, msg });
+}
+
+function checkData(response, data_head, cb) {
+ ok(response, "Data is non-null");
+ var str = String.fromCharCode.apply(null, new Uint8Array(response));
+ ok(str.length == data_head.length + gPaddingSize, "Data size is correct");
+ ok(str.slice(0, data_head.length) == data_head, "Data head is correct");
+ ok(str.slice(data_head.length) == gPadding, "Data padding is correct");
+ cb();
+}
+
+self.onmessage = function onmessage(event) {
+ var jar = event.data;
+
+ function makeJarURL(entry) {
+ return "jar:" + jar + "!/" + entry;
+ }
+
+ function test_mapped_sync() {
+ var xhr = new XMLHttpRequest({ mozAnon: true, mozSystem: true });
+ xhr.open("GET", makeJarURL("data_1.txt"), false);
+ xhr.responseType = "arraybuffer";
+ xhr.send();
+ if (xhr.status) {
+ ok(xhr.status == 200, "Status is 200");
+ var ct = xhr.getResponseHeader("Content-Type");
+ ok(ct.includes("mem-mapped"), "Data is memory-mapped");
+ checkData(xhr.response, gData1, runTests);
+ }
+ }
+
+ function test_mapped_async() {
+ var xhr = new XMLHttpRequest({ mozAnon: true, mozSystem: true });
+ xhr.open("GET", makeJarURL("data_1.txt"));
+ xhr.responseType = "arraybuffer";
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState !== xhr.DONE) {
+ return;
+ }
+ if (xhr.status) {
+ ok(xhr.status == 200, "Status is 200");
+ var ct = xhr.getResponseHeader("Content-Type");
+ ok(ct.includes("mem-mapped"), "Data is memory-mapped");
+ checkData(xhr.response, gData1, runTests);
+ }
+ };
+ xhr.send();
+ }
+
+ // Make sure array buffer retrieved from compressed file in package is
+ // handled by memory allocation instead of memory mapping.
+ function test_non_mapped() {
+ var xhr = new XMLHttpRequest({ mozAnon: true, mozSystem: true });
+ xhr.open("GET", makeJarURL("data_2.txt"));
+ xhr.responseType = "arraybuffer";
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState !== xhr.DONE) {
+ return;
+ }
+ if (xhr.status) {
+ ok(xhr.status == 200, "Status is 200");
+ var ct = xhr.getResponseHeader("Content-Type");
+ ok(!ct.includes("mem-mapped"), "Data is not memory-mapped");
+ checkData(xhr.response, gData2, runTests);
+ }
+ };
+ xhr.send();
+ }
+
+ var tests = [test_mapped_sync, test_mapped_async, test_non_mapped];
+
+ function runTests() {
+ if (!tests.length) {
+ postMessage({ type: "finish" });
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+ }
+
+ runTests();
+};
diff --git a/dom/base/test/file_change_policy_redirect.html b/dom/base/test/file_change_policy_redirect.html
new file mode 100644
index 0000000000..e48386d97c
--- /dev/null
+++ b/dom/base/test/file_change_policy_redirect.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ parent.postMessage('childLoadComplete', 'http://mochi.test:8888');
+ </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/base/test/file_current_inner_window.html b/dom/base/test/file_current_inner_window.html
new file mode 100644
index 0000000000..8156e29000
--- /dev/null
+++ b/dom/base/test/file_current_inner_window.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title></title>
+ <script>
+ function isCurrentWinnerWindow() {
+ // If we are the current inner window for our BrowsingContext, bare word
+ // access to `name` will return "". If we are not, it will throw.
+ // Note that this is *not* the same as accessing `window.name`, which
+ // will go through our WindowProxy, which will always forward it to the
+ // currently-active inner window.
+ try {
+ void name;
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+ </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/base/test/file_delazification_strategy.html b/dom/base/test/file_delazification_strategy.html
new file mode 100644
index 0000000000..a8f58c60f1
--- /dev/null
+++ b/dom/base/test/file_delazification_strategy.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Add a tag script to check delazification strategy</title>
+</head>
+<body>
+ <!-- <script id="watchme" src="file_delazification_strategy.js"></script> -->
+</body>
+</html>
diff --git a/dom/base/test/file_delazification_strategy.js b/dom/base/test/file_delazification_strategy.js
new file mode 100644
index 0000000000..5afcbeed53
--- /dev/null
+++ b/dom/base/test/file_delazification_strategy.js
@@ -0,0 +1,91 @@
+function baz() {}
+function bar() {}
+function foo() {
+ bar();
+}
+foo();
+
+// For testing, we require the script to be parsed off-htread. To schedule a
+// script off-thread, we require the script to be at least 5 KB. Thus, here is
+// one comment which is used to trick this heuristics:
+//
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWWX0Oxoc;,.... ....,;coxO0XWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0kdlc;'.. ..';:ldk0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNKkoc,.. ..,cok0NWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKko:'. .':okKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKkl,. .,lkKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;. .;oONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkl'. 'lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOl' 'lONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMWKo, ,oKWMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMNk:. .:kNMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMXx, ,xXMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMWXd' 'dXWMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMXd' 'dXMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMNx' 'xNMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMWO; ;OWMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMKl. .lXMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMWk, ,kWMMMMMMMMMMMMM
+// MMMMMMMMMMMMXo. .lXMMMMMMMMMMMM
+// MMMMMMMMMMW0; ...... ;0WMMMMMMMMMM
+// MMMMMMMMMWk' ..,:loxxkOOkxdo:,. 'kWMMMMMMMMM
+// MMMMMMMMWx. .':lxO000000000000000ko;. .xWMMMMMMMM
+// MMMMMMMNd. .'cdk00000000000000000000000x;. ..',;ccloodddddddollc:;,'.. .dNMMMMMMM
+// MMMMMMNd. ,dO000000000000000000000000000Oo' ..;coxk00000000000000000000000Okdlc;'. .dNMMMMMM
+// MMMMMNd. .cO000000000000000000000000000000k; .;lxO0000000000000000000000000000000000Okoc,. .dWMMMMM
+// MMMMWx. .'cO0000000000000000000000000000Oc. .;ok0000K00000000000000000000000000000000000000ko, .kWMMMM
+// MMMMO' ,kK0000000000000000000000000000Oc. .:x000000000000000OkdoollcccllodxkO0000K00000000000k' 'OMMMM
+// MMMK; .'lO000000000000000000000000000000Ol'... 'd000000000000Odl;'.. ..',:ldkO00000000KO, ;KMMM
+// MMNo ,dkO0K00000000000000000000000000000000OOkxdoc;,,ck0000000000Oo;. .'ck000000KO; oNMM
+// MMk. .o0000000000000000000000000000000000000000000000000000000000d, .o000000K0: .OMM
+// MX: .o00000000000000000000000000000000000000000000000000000000Oc. c000000K0l. :XM
+// Wx. .c00000000000000000000000000000000000000000000000000000000x, :OK000000o. .xW
+// X: .:dxO00000000000000000000000000000000000000000000000000000Oo' ,k0000000d. :X
+// O. .:xOO0000000000000000000000000000000000000000000000000000Ol. .x000000Kd. .O
+// o ..'''''''',,:lx000000000000000000000000000000000000000000x, .lOOOOkkko. o
+// ; .:x00000000000000000000000000000000000000000O:. ......... ;
+// . 'd00000000000000000000000000000000000000000Ol. .
+// . ,k000000000000000000000000000000000000000000o. .
+// .o0000000000000000000000000000000000000000000d.
+// c00000000000000000000000000000000000000000000o.
+// ;OK0000000000000000000000000000000000000000000o.
+// ,kK00000000000000000000000000000000000000000000xoc:,'..
+// .x00000000000000000000000000000000000000000000000000Okxolc;,'..
+// .d000000000000000K000000000000000000000000000000000000000000OOxdl:,..
+// . .o00000000000000OO0000000000000000000000000000000000000000000000000Oxo:'. .
+// . .l0000000000000Oc:k0000000000000000000000000000000000000000000000000000Oxl,. .
+// ; c000000000000Kk, ,x000000000000000000000000000000xodkO00000000000000000000xc. ;
+// o ..''.. :000000000000Kx' ,k0000000000000000000000000000Oc. ..';codkO000000000000000k:. o
+// O. .,lxO00Okxl:,. :O000000000000d. ;k0000000000000000000000000000l. ..,cok0000000000000d' .O
+// X: ,d000000000000kdc;. :O000000000000l. .c0000000000000000000000000000o. .;oO00000000000k; :X
+// Wx. 'x00000000000000000Oxl;..:O00000000000O: .x000000000000000000000000000d. 'oO00000K0000k, .kW
+// MX: c0000000000000000000000Oxk00000000000Kk, cO00000000000000000000000000d. ;k0000000000d. :XM
+// MMO. :O000000000000000000000000000000000000x. cO00000000000000000000000000d. ,k000000000O: .OMM
+// MMNo .d000000000000000000000000000000000000l. .d000000000000000000000000000o. cO000000000o. .oNMM
+// MMMK; 'd00000000000000000000000000000000000c ,k000000000000000000000000000l. 'x000000000d. ;KMMM
+// MMMMO' .lO000000000000000000000000000000000kl;. .o00000000000000000000000000K0c .d000000000d. 'OMMMM
+// MMMMWx. ;x00000000000000000000000000000000000ko:lO000000000000000000000000000O; .x000000000d. .xWMMMM
+// MMMMMWd. .ck00000000000000000000000000000000000000000000000000000000000000000k, ;kK00000000l. .dWMMMMM
+// MMMMMMNd. .:x000000000000000000000000000000000000000000000000000000000000000d. .o000000000O; .dNMMMMMM
+// MMMMMMMNd. .;dO000000000000000000000000000000000000000000000000000000000000l. .o0000000000d. .dNMMMMMMM
+// MMMMMMMMWx. .,,'.. 'cx00000000000000000000000000000000000000000000000000000000KO: .;d0000000000x, .xWMMMMMMMM
+// MMMMMMMMMWk' 'd00Oxdl;'. .,lx000000000000000000000000000000000000000000000000000000k' .:dO0000000000x, 'kWMMMMMMMMM
+// MMMMMMMMMMW0; .:x000000kd:'. .,lk000000000000000000000000000000000000000000000000000d. ..,cdk0K000000000Oo. :0WMMMMMMMMMM
+// MMMMMMMMMMMMXo. .,ok000000Odc. ,x000000000000000000000000000000000000000000000000000d,...'',;:cldxO000000000000K0d;. .oXMMMMMMMMMMMM
+// MMMMMMMMMMMMMWk, .:x0000000Oo;.. .,oO000000000000000000000000000000000000000000000000000000OOOO00000000000000000000Od;. ,kWMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMXl. .;dO0000000Oxdoooxk0000000000OxxO0000000000000000000000000000000000000000000000000000000000000000Oxc' .lXMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMWO; 'lk00000000000000000000Oxc' ..:oxO0K000000000000000000000000000000000000000000000000000000Oko:'. ;OWMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMNx, .;ok00000000000000kdc'. ..;cdxO00000000000000000000000000000000000000000000Okxdoc;'. ,xNMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMXd' .,:ldxkkkkxdl:,. ..,:cldxkkkO000000000000Okkxdlc:;;;:::::;;;,,'... 'dXMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMXd' ...... ....'',,,,,,,,'.... 'dXWMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMXx,. ,xXMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMNk:. .:kNMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMWKo,. .,oKWMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOl' 'lONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXkl'. .'lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;. .;oONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKkl;. .,lkKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKko:'. .':okKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNKkoc,.. ..,cok0NWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0kdlc;'.. ..';:ldk0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWWX0Oxoc;,.... ....,;coxO0XNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
diff --git a/dom/base/test/file_domwindowutils_animation.html b/dom/base/test/file_domwindowutils_animation.html
new file mode 100644
index 0000000000..dfcc8fc05c
--- /dev/null
+++ b/dom/base/test/file_domwindowutils_animation.html
@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>DOMWindowUtils test with animation</title>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <script src="/tests/dom/animation/test/testcommon.js"></script>
+</head>
+<body>
+<script type="application/javascript">
+
+const SimpleTest = window.opener.SimpleTest;
+const utils = SpecialPowers.getDOMWindowUtils(window);
+const next = window.opener.next;
+const is = window.opener.is;
+const ok = window.opener.ok;
+
+function addStyle(rules) {
+ const extraStyle = document.createElement("style");
+ document.head.appendChild(extraStyle);
+ rules.forEach(rule => {
+ extraStyle.sheet.insertRule(rule, extraStyle.sheet.cssRules.length);
+ });
+}
+
+function deleteStyle() {
+ document.head.querySelector("style").remove();
+}
+
+
+function test_getUnanimatedComputedStyle() {
+ [
+ {
+ property: "opacity",
+ keyframes: [1, 0],
+ expectedInitialStyle: "1",
+ expectedDuringTransitionStyle: "0",
+ isDiscrete: false,
+ },
+ {
+ property: "clear",
+ keyframes: ["left", "inline-end"],
+ expectedInitialStyle: "none",
+ expectedDuringTransitionStyle: "inline-end",
+ isDiscrete: true,
+ },
+ ].forEach(testcase => {
+ const { property, keyframes, expectedInitialStyle,
+ expectedDuringTransitionStyle, isDiscrete } = testcase;
+
+ [null, "unset", "initial", "inherit"].forEach(initialStyle => {
+ const scriptAnimation = target => {
+ return target.animate({ [property]: keyframes }, 1000);
+ }
+ checkUnanimatedComputedStyle(property, initialStyle, null,
+ expectedInitialStyle, expectedInitialStyle,
+ scriptAnimation, "script animation");
+
+ const cssAnimationStyle = `@keyframes cssanimation {`
+ + ` from { ${property}: ${ keyframes[0] }; }`
+ + ` to { ${property}: ${ keyframes[1] }; } }`;
+ addStyle([cssAnimationStyle]);
+ const cssAnimation = target => {
+ target.style.animation = "cssanimation 1s";
+ return target.getAnimations()[0];
+ }
+ checkUnanimatedComputedStyle(property, initialStyle, null,
+ expectedInitialStyle, expectedInitialStyle,
+ cssAnimation, "CSS Animations");
+ deleteStyle();
+
+ // We don't support discrete animations for CSS Transitions yet.
+ // (bug 1320854)
+ if (!isDiscrete) {
+ const cssTransition = target => {
+ target.style[property] = keyframes[0];
+ target.style.transition =
+ `${ property } 1s`;
+ window.getComputedStyle(target)[property];
+ target.style[property] = keyframes[1];
+ return target.getAnimations()[0];
+ }
+ checkUnanimatedComputedStyle(property, initialStyle, null,
+ expectedInitialStyle,
+ expectedDuringTransitionStyle,
+ cssTransition, "CSS Transitions");
+ }
+
+ addStyle([cssAnimationStyle,
+ ".pseudo::before { content: '' }",
+ ".animation::before { animation: cssanimation 1s }"]);
+ const pseudoAnimation = target => {
+ target.classList.add("animation");
+ return target.getAnimations({ subtree: true })[0];
+ }
+ checkUnanimatedComputedStyle(property, initialStyle, "::before",
+ expectedInitialStyle, expectedInitialStyle,
+ pseudoAnimation, "Animation at pseudo");
+ deleteStyle();
+ });
+ });
+
+ const div = document.createElement("div");
+ document.body.appendChild(div);
+
+ SimpleTest.doesThrow(
+ () => utils.getUnanimatedComputedStyle(div, null, "background", utils.FLUSH_NONE),
+ "NS_ERROR_INVALID_ARG",
+ "Shorthand property should throw");
+
+ SimpleTest.doesThrow(
+ () => utils.getUnanimatedComputedStyle(div, null, "invalid", utils.FLUSH_NONE),
+ "NS_ERROR_INVALID_ARG",
+ "Invalid property should throw");
+
+ SimpleTest.doesThrow(
+ () => utils.getUnanimatedComputedStyle(null, null, "opacity", utils.FLUSH_NONE),
+ "NS_ERROR_INVALID_ARG",
+ "Null element should throw");
+
+ SimpleTest.doesThrow(
+ () => utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_LAYOUT),
+ "NS_ERROR_INVALID_ARG",
+ "FLUSH_LAYOUT option should throw");
+
+ SimpleTest.doesThrow(
+ () => utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_DISPLAY),
+ "NS_ERROR_INVALID_ARG",
+ "FLUSH_DISPLAY option should throw");
+
+ SimpleTest.doesThrow(
+ () => utils.getUnanimatedComputedStyle(div, "::before", "opacity", utils.FLUSH_NONE),
+ "NS_ERROR_FAILURE",
+ "Non-existent pseudo should throw");
+
+ // Flush styles since getUnanimatedComputedStyle flushes pending styles even
+ // with FLUSH_NONE option if the element hasn't yet styled.
+ getComputedStyle(div).opacity;
+
+ div.style.opacity = "0";
+ is(utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_NONE),
+ "1",
+ "getUnanimatedComputedStyle with FLUSH_NONE should not flush pending styles");
+
+ is(utils.getUnanimatedComputedStyle(div, null, "opacity", utils.FLUSH_STYLE),
+ "0",
+ "getUnanimatedComputedStyle with FLUSH_STYLE should flush pending styles");
+
+ div.remove();
+
+ test_needsFlushWithThrottledAnimations();
+}
+
+function checkUnanimatedComputedStyle(property, initialStyle, pseudoType,
+ expectedBeforeAnimation,
+ expectedDuringAnimation,
+ animate, animationType) {
+ const div = document.createElement("div");
+ document.body.appendChild(div);
+
+ if (initialStyle) {
+ div.style[property] = initialStyle;
+ }
+ if (pseudoType) {
+ div.classList.add("pseudo");
+ }
+
+ is(utils.getUnanimatedComputedStyle(div, pseudoType, property, utils.FLUSH_STYLE),
+ expectedBeforeAnimation,
+ `'${ property }' property with '${ initialStyle }' style `
+ + `should be '${ expectedBeforeAnimation }' `
+ + `before animating by ${ animationType }`);
+
+ const animation = animate(div);
+ animation.currentTime = 500;
+ is(utils.getUnanimatedComputedStyle(div, pseudoType, property, utils.FLUSH_STYLE),
+ expectedDuringAnimation,
+ `'${ property }' property with '${ initialStyle }' style `
+ + `should be '${ expectedDuringAnimation }' `
+ + `even while animating by ${ animationType }`);
+
+ div.remove();
+}
+
+function test_needsFlushWithThrottledAnimations() {
+ const div = document.createElement("div");
+ div.style = "width: 100px; height: 100px; background-color: blue;";
+ document.body.appendChild(div);
+
+ const animation = div.animate({ opacity: [ 0, 1 ] },
+ { duration: 100000, iterations: Infinity });
+ waitForAnimationReadyToRestyle(animation).then(() => {
+ ok(SpecialPowers.wrap(animation).isRunningOnCompositor,
+ "Opacity animation should run on the compositor");
+
+ // FIXME! Bug 1442861: We should make sure needsFlush() returns true
+ // before flusing layout.
+ //ok(utils.needsFlush(SpecialPowers.Ci.nsIDOMWindowUtils.FLUSH_STYLE),
+ // "needsFlush should return true if there is an animation on the compositor");
+
+ // Flush layout.
+ document.documentElement.getBoundingClientRect();
+
+ ok(!utils.needsFlush(SpecialPowers.Ci.nsIDOMWindowUtils.FLUSH_STYLE),
+ "needsFlush should return false after flushing layout");
+
+ div.remove();
+ next();
+ window.close();
+ });
+}
+
+window.addEventListener("load", test_getUnanimatedComputedStyle);
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_domwindowutils_dynamic_toolbar.html b/dom/base/test/file_domwindowutils_dynamic_toolbar.html
new file mode 100644
index 0000000000..becb4bf08f
--- /dev/null
+++ b/dom/base/test/file_domwindowutils_dynamic_toolbar.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+ const ok = window.opener.ok;
+
+ SpecialPowers.getDOMWindowUtils(window).setDynamicToolbarMaxHeight(100);
+ ok(window.visualViewport.width > 0,
+ "Setting the dynamic toolbar max height shouldn't clobber the visual " +
+ "viewport size");
+ ok(window.visualViewport.height > 0,
+ "Setting the dynamic toolbar max height shouldn't clobber the visual " +
+ "viewport size");
+
+ window.opener.next();
+ window.close();
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_empty.html b/dom/base/test/file_empty.html
new file mode 100644
index 0000000000..495c23ec8a
--- /dev/null
+++ b/dom/base/test/file_empty.html
@@ -0,0 +1 @@
+<!DOCTYPE html><html><body></body></html>
diff --git a/dom/base/test/file_explicit_user_agent.sjs b/dom/base/test/file_explicit_user_agent.sjs
new file mode 100644
index 0000000000..33b9a5c505
--- /dev/null
+++ b/dom/base/test/file_explicit_user_agent.sjs
@@ -0,0 +1,6 @@
+function handleRequest(request, response) {
+ if (request.hasHeader("User-Agent")) {
+ response.setHeader("Result-User-Agent", request.getHeader("User-Agent"));
+ }
+ response.write("");
+}
diff --git a/dom/base/test/file_external_script.html b/dom/base/test/file_external_script.html
new file mode 100644
index 0000000000..16f059d558
--- /dev/null
+++ b/dom/base/test/file_external_script.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="file_script.js"></script>
+ <meta charset="utf-8">
+ <title></title>
+</head>
+<body>
+ <p>Hello Mochitest</p>
+</body>
+</html>
diff --git a/dom/base/test/file_external_script.xhtml b/dom/base/test/file_external_script.xhtml
new file mode 100644
index 0000000000..4327c499cb
--- /dev/null
+++ b/dom/base/test/file_external_script.xhtml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <script src="file_script.js"/>
+ <title/>
+</head>
+<body>
+ <p>Hello Mochitest</p>
+</body>
+</html>
diff --git a/dom/base/test/file_focus_design_mode_inner.html b/dom/base/test/file_focus_design_mode_inner.html
new file mode 100644
index 0000000000..43e24652ab
--- /dev/null
+++ b/dom/base/test/file_focus_design_mode_inner.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>activeElement design-mode inner document</title>
+</head>
+<body>
+<h1>Inner</h1>
+<script>
+let innerlog = "innerlog:";
+
+document.designmode = "on";
+
+window.onmessage = function(e) {
+ if (e.data == "focus") {
+ document.documentElement.focus();
+ } else if (e.data == "getlog") {
+ innerlog += "activeElement:" + document.activeElement.tagName + ",";
+ parent.postMessage(innerlog, "*");
+ }
+};
+
+window.onfocus = function() {
+ innerlog += "windowfocus,";
+};
+
+window.onblur = function() {
+ innerlog += "windowblur,";
+};
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_focus_display_none_xorigin_iframe_inner.html b/dom/base/test/file_focus_display_none_xorigin_iframe_inner.html
new file mode 100644
index 0000000000..5831df882c
--- /dev/null
+++ b/dom/base/test/file_focus_display_none_xorigin_iframe_inner.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<h2>Inner</h2>
+<input></input><br>
+<script type="text/javascript">
+let input = document.querySelector("input");
+
+window.onmessage = function(e) {
+ info(`inner received message: ${e.data}`);
+ if (e.data === "focus") {
+ input.focus();
+ window.parent.postMessage("done", "*");
+ }
+};
+</script>
diff --git a/dom/base/test/file_focus_shadow_dom.html b/dom/base/test/file_focus_shadow_dom.html
new file mode 100644
index 0000000000..6fa9d1b88e
--- /dev/null
+++ b/dom/base/test/file_focus_shadow_dom.html
@@ -0,0 +1,999 @@
+<html>
+ <head>
+ <title>Test for Bug 1453693</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script>
+
+ class TestNode extends HTMLElement {
+ constructor() {
+ super();
+ const styles = "<style>:focus{background-color:yellow;}</style>";
+ this.attachShadow({ mode: 'open' });
+ this.shadowRoot.innerHTML =
+ `${styles}<div tabindex='-1'>test node</div> <slot></slot>`;
+ }}
+
+ window.customElements.define('test-node', TestNode);
+
+ var lastFocusTarget;
+ function focusLogger(event) {
+ lastFocusTarget = event.target;
+ console.log(event.target + " under " + event.target.parentNode);
+ event.stopPropagation();
+ }
+
+ function testTabbingThroughShadowDOMWithTabIndexes() {
+ var anchor = document.createElement("a");
+ anchor.onfocus = focusLogger;
+ anchor.href = "#";
+ anchor.textContent = "in light DOM";
+ document.body.appendChild(anchor);
+
+ var host = document.createElement("div");
+ document.body.appendChild(host);
+
+ var sr = host.attachShadow({mode: "open"});
+ var shadowAnchor = anchor.cloneNode(false);
+ shadowAnchor.onfocus = focusLogger;
+ shadowAnchor.textContent = "in shadow DOM";
+ sr.appendChild(shadowAnchor);
+ var shadowInput = document.createElement("input");
+ shadowInput.onfocus = focusLogger;
+ shadowInput.tabIndex = 1;
+ sr.appendChild(shadowInput);
+
+ var shadowDate = document.createElement("input");
+ shadowDate.type = "date";
+ shadowDate.onfocus = focusLogger;
+ shadowDate.tabIndex = 1;
+ sr.appendChild(shadowDate);
+
+ var shadowIframe = document.createElement("iframe");
+ shadowIframe.tabIndex = 1;
+ sr.appendChild(shadowIframe);
+ shadowIframe.contentDocument.body.innerHTML = "<input>";
+
+ var input = document.createElement("input");
+ input.onfocus = focusLogger;
+ input.tabIndex = 1;
+ document.body.appendChild(input);
+
+ var input2 = document.createElement("input");
+ input2.onfocus = focusLogger;
+ document.body.appendChild(input2);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input, "Should have focused input element. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, anchor, "Should have focused anchor element. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element with a calendar button in shadow DOM. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(shadowIframe.contentDocument.activeElement,
+ shadowIframe.contentDocument.documentElement,
+ "Should have focused document element in shadow iframe. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(shadowIframe.contentDocument.activeElement,
+ shadowIframe.contentDocument.body.firstChild,
+ "Should have focused input element in shadow iframe. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowAnchor, "Should have focused anchor element in shadow DOM. (3)");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input2, "Should have focused input[2] element. (3)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowAnchor, "Should have focused anchor element in shadow DOM. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(shadowIframe.contentDocument.activeElement,
+ shadowIframe.contentDocument.body.firstChild,
+ "Should have focused input element in shadow iframe. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(shadowIframe.contentDocument.activeElement,
+ shadowIframe.contentDocument.documentElement,
+ "Should have focused document element in shadow iframe. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element with a calendar button in shadow DOM. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, anchor, "Should have focused anchor element. (4)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input, "Should have focused input element. (4)");
+
+ document.body.innerHTML = null;
+ }
+
+ function testTabbingThroughSimpleShadowDOM() {
+ var anchor = document.createElement("a");
+ anchor.onfocus = focusLogger;
+ anchor.href = "#";
+ anchor.textContent = "in light DOM";
+ document.body.appendChild(anchor);
+ anchor.focus();
+
+ var host = document.createElement("div");
+ document.body.appendChild(host);
+
+ var sr = host.attachShadow({mode: "open"});
+ var shadowAnchor = anchor.cloneNode(false);
+ shadowAnchor.onfocus = focusLogger;
+ shadowAnchor.textContent = "in shadow DOM";
+ sr.appendChild(shadowAnchor);
+ var shadowInput = document.createElement("input");
+ shadowInput.onfocus = focusLogger;
+ sr.appendChild(shadowInput);
+
+ var hiddenShadowButton = document.createElement("button");
+ hiddenShadowButton.setAttribute("style", "display: none;");
+ sr.appendChild(hiddenShadowButton);
+
+ var input = document.createElement("input");
+ input.onfocus = focusLogger;
+ document.body.appendChild(input);
+
+ var input2 = document.createElement("input");
+ input2.onfocus = focusLogger;
+ document.body.appendChild(input2);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowAnchor, "Should have focused anchor element in shadow DOM.");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM.");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input, "Should have focused input element.");
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input2, "Should have focused input[2] element.");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input, "Should have focused input element. (2)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM. (2)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowAnchor, "Should have focused anchor element in shadow DOM. (2)");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, anchor, "Should have focused anchor element. (2)");
+
+ host.remove();
+ input.remove();
+ input2.remove();
+ }
+
+ function testTabbingThroughNestedShadowDOM() {
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (1)");
+
+ var host = document.createElement("div");
+ host.id = "host";
+ document.body.appendChild(host);
+
+ var sr0 = host.attachShadow({mode: "open"});
+ sr0.innerHTML = "<button id='button'>X</button><br id='br'><div id='h1'></div><div id='h2'></div>";
+ var button = sr0.getElementById("button");
+ button.onfocus = focusLogger;
+
+ var h1 = sr0.getElementById("h1");
+ var sr1 = h1.attachShadow({mode: "open"});
+ sr1.innerHTML = "h1 <input id='h11' placeholder='click me and press tab'><input id='h12' placeholder='and then tab again'>";
+ var input11 = sr1.getElementById("h11");
+ input11.onfocus = focusLogger;
+ var input12 = sr1.getElementById("h12");
+ input12.onfocus = focusLogger;
+
+ var h2 = sr0.getElementById("h2");
+ var sr2 = h2.attachShadow({mode: "open"});
+ sr2.innerHTML = "h2 <input id='h21'><input id='h22'>";
+ var input21 = sr2.getElementById("h21");
+ input21.onfocus = focusLogger;
+ var input22 = sr2.getElementById("h22");
+ input22.onfocus = focusLogger;
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, button, "[nested shadow] Should have focused button element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input11, "[nested shadow] Should have focused input element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input12, "[nested shadow] Should have focused input element. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input21, "[nested shadow] Should have focused input element. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input22, "[nested shadow] Should have focused input element. (4)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input21, "[nested shadow] Should have focused input element. (5)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input12, "[nested shadow] Should have focused input element. (6)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input11, "[nested shadow] Should have focused input element. (7)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, button, "[nested shadow] Should have focused button element. (8)");
+
+ // Back to beginning, outside of Shadow DOM.
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (2)");
+
+ host.remove();
+ }
+
+ function testTabbingThroughDisplayContentsHost() {
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (1)");
+
+ var host = document.createElement("div");
+ host.id = "host";
+ host.setAttribute("style", "display: contents; border: 1px solid black;");
+ document.body.appendChild(host);
+
+ var sr0 = host.attachShadow({mode: "open"});
+ sr0.innerHTML = "<input id='shadowInput1'><input id='shadowInput2'>";
+ var shadowInput1 = sr0.getElementById("shadowInput1");
+ shadowInput1.onfocus = focusLogger;
+ var shadowInput2 = sr0.getElementById("shadowInput2");
+ shadowInput2.onfocus = focusLogger;
+
+ var host1 = document.createElement("div");
+ host1.id = "host";
+ host1.tabIndex = 0;
+ host1.setAttribute("style", "display: contents; border: 1px solid black;");
+ document.body.appendChild(host1);
+
+ var sr1 = host1.attachShadow({mode: "open"});
+ sr1.innerHTML = "<input id='shadowInput1'><input id='shadowInput2'>";
+ var shadowInput3 = sr1.getElementById("shadowInput1");
+ shadowInput3.onfocus = focusLogger;
+ var shadowInput4 = sr1.getElementById("shadowInput2");
+ shadowInput4.onfocus = focusLogger;
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowInput1, "Should have focused input element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowInput2, "Should have focused input element. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowInput3, "Should have focused input element. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowInput4, "Should have focused input element. (4)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowInput3, "Should have focused input element. (5)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowInput2, "Should have focused input element. (6)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowInput1, "Should have focused input element. (7)");
+
+ // Back to beginning, outside of Shadow DOM.
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (2)");
+
+ host.remove();
+ host1.remove();
+ }
+
+ function testTabbingThroughLightDOMShadowDOMLightDOM() {
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ var host = document.createElement("span");
+ host.innerHTML = "\n";
+ host.id = "host";
+ document.body.appendChild(host);
+
+ var sr0 = host.attachShadow({mode: "open"});
+ sr0.innerHTML = document.getElementById("template").innerHTML;
+ var p1 = sr0.getElementById("p1");
+ p1.onfocus = focusLogger;
+ var p2 = sr0.getElementById("p2");
+ p2.onfocus = focusLogger;
+
+ var p = document.createElement("p");
+ p.innerHTML = " <a href='#p'>link 1</a> ";
+ var a = p.firstElementChild;
+ a.onfocus = focusLogger;
+ document.body.appendChild(p);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, p1, "Should have focused p1.");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, p2, "Should have focused p2.");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, a, "Should have focused a.");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, p2, "Should have focused p2.");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, p1, "Should have focused p1.");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ host.remove();
+ p.remove();
+ }
+
+ function testFocusableHost() {
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ var host = document.createElement("div");
+ host.id = "host";
+ host.tabIndex = 0;
+ host.onfocus = focusLogger;
+ document.body.appendChild(host);
+
+ var slotted = document.createElement("div");
+ slotted.tabIndex = 0;
+ slotted.onfocus = focusLogger;
+ host.appendChild(slotted);
+
+ var sr0 = host.attachShadow({mode: "open"});
+ sr0.appendChild(document.createElement("slot"));
+
+ var p = document.createElement("p");
+ p.innerHTML = " <a href='#p'>link 1</a> ";
+ var a = p.firstElementChild;
+ a.onfocus = focusLogger;
+ document.body.appendChild(p);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, host, "Should have focused host.");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, slotted, "Should have focused slotted.");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, a, "Should have focused a.");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, slotted, "Should have focused slotted.");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, host, "Should have focused host.");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ host.remove();
+ p.remove();
+ }
+
+ function testShiftTabbingThroughFocusableHost() {
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ var host = document.createElement("div");
+ host.id = "host";
+ host.tabIndex = 0;
+ host.onfocus = focusLogger;
+ document.body.appendChild(host);
+
+ var sr = host.attachShadow({mode: "open"});
+ var shadowButton = document.createElement("button");
+ shadowButton.innerText = "X";
+ shadowButton.onfocus = focusLogger;
+ sr.appendChild(shadowButton);
+
+ var shadowInput = document.createElement("input");
+ shadowInput.onfocus = focusLogger;
+ sr.appendChild(shadowInput);
+ sr.appendChild(document.createElement("br"));
+
+ var input = document.createElement("input");
+ input.onfocus = focusLogger;
+ document.body.appendChild(input);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, host, "Should have focused host element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowButton, "Should have focused button element in shadow DOM. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input, "Should have focused input element. (4)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM. (5)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, shadowButton, "Should have focused button element in shadow DOM. (6)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ // focus is already on host
+ opener.is(sr.activeElement, null,
+ "Focus should have left button element in shadow DOM. (7)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ host.remove();
+ input.remove();
+ }
+
+ function testTabbingThroughNestedSlot() {
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus.");
+
+ var host0 = document.createElement("div");
+ var sr0 = host0.attachShadow({mode: "open"});
+ sr0.innerHTML = "<slot></slot>";
+ document.body.appendChild(host0);
+
+ // focusable
+ var host00 = document.createElement("div");
+ var sr00 = host00.attachShadow({mode: "open"});
+ var div00 = document.createElement("div");
+ div00.tabIndex = 0;
+ div00.onfocus = focusLogger;
+ sr00.appendChild(div00);
+ host0.appendChild(host00);
+
+ // not focusable
+ var host01 = document.createElement("div");
+ var sr01 = host01.attachShadow({mode: "open"});
+ sr01.innerHTML = "<div></div>";
+ host0.appendChild(host01);
+
+ // focusable
+ var host02 = document.createElement("div");
+ var sr02 = host02.attachShadow({mode: "open"});
+ var div02 = document.createElement("div");
+ div02.tabIndex = 0;
+ div02.onfocus = focusLogger;
+ sr02.appendChild(div02);
+ host0.appendChild(host02);
+
+ var host1 = document.createElement("div");
+ var sr1 = host1.attachShadow({mode: "open"});
+ sr1.innerHTML = "<slot></slot>";
+ document.body.appendChild(host1);
+
+ var host10 = document.createElement("div");
+ var sr10 = host10.attachShadow({mode: "open"});
+ sr10.innerHTML = "<slot></slot>";
+ host1.appendChild(host10);
+
+ var input10 = document.createElement("input");
+ input10.onfocus = focusLogger;
+ host10.appendChild(input10);
+
+ var host11 = document.createElement("div");
+ var sr11 = host11.attachShadow({mode: "open"});
+ sr11.innerHTML = "<slot></slot>";
+ host1.appendChild(host11);
+
+ var input11 = document.createElement("input");
+ input11.onfocus = focusLogger;
+ host11.appendChild(input11);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, div00, "Should have focused div element in shadow DOM. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, div02, "Should have focused div element in shadow DOM. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input10, "Should have focused input element in shadow DOM. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input11, "Should have focused button element in shadow DOM. (4)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input10, "Should have focused input element in shadow DOM. (5)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, div02, "Should have focused input element in shadow DOM. (6)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, div00, "Should have focused input element in shadow DOM. (7)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ host0.remove();
+ host1.remove();
+ }
+
+ function testTabbingThroughSlotInLightDOM() {
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus.");
+
+ var input0 = document.createElement("input");
+ input0.onfocus = focusLogger;
+ document.body.appendChild(input0);
+
+ var slot1 = document.createElement("slot");
+ document.body.appendChild(slot1);
+
+ var input10 = document.createElement("input");
+ input10.onfocus = focusLogger;
+ slot1.appendChild(input10);
+
+ var input11 = document.createElement("input");
+ input11.onfocus = focusLogger;
+ slot1.appendChild(input11);
+
+ var input2 = document.createElement("input");
+ input2.onfocus = focusLogger;
+ document.body.appendChild(input2);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input0, "Should have focused input element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input10, "Should have focused input element in slot. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input11, "Should have focused input element in slot. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input2, "Should have focused input element. (4)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input11, "Should have focused input element in slot. (5)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input10, "Should have focused input element in slot. (6)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input0, "Should have focused input element. (7)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ input0.remove();
+ slot1.remove();
+ input2.remove();
+ }
+
+ function testTabbingThroughFocusableSlotInLightDOM() {
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus.");
+
+ var slot0 = document.createElement("slot");
+ slot0.tabIndex = 0;
+ slot0.setAttribute("style", "display: inline;");
+ slot0.onfocus = focusLogger;
+ document.body.appendChild(slot0);
+
+ var slot00 = document.createElement("slot");
+ slot00.tabIndex = 0;
+ slot00.setAttribute("style", "display: inline;");
+ slot00.onfocus = focusLogger;
+ slot0.appendChild(slot00);
+
+ var input000 = document.createElement("input");
+ input000.onfocus = focusLogger;
+ slot00.appendChild(input000);
+
+ var input01 = document.createElement("input");
+ input01.onfocus = focusLogger;
+ slot0.appendChild(input01);
+
+ var input1 = document.createElement("input");
+ input1.onfocus = focusLogger;
+ document.body.appendChild(input1);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, slot0, "Should have focused slot element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, slot00, "Should have focused slot element. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input000, "Should have focused input element in slot. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input01, "Should have focused input element in slot. (4)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input1, "Should have focused input element. (5)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input01, "Should have focused input element in slot. (6)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input000, "Should have focused input element in slot. (7)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, slot00, "Should have focused slot element. (8)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, slot0, "Should have focused slot element. (9)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ slot0.remove();
+ input1.remove();
+ }
+
+ function testTabbingThroughScrollableShadowDOM() {
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus.");
+
+ var host0 = document.createElement("div");
+ host0.setAttribute("style", "height: 50px; overflow: auto;");
+ host0.onfocus = focusLogger;
+ document.body.appendChild(host0);
+
+ var sr0 = host0.attachShadow({mode: "open"});
+ sr0.innerHTML = `
+ <style>
+ div,slot {
+ height: 30px;
+ display: block;
+ overflow: auto;
+ }
+ input {
+ display: block;
+ }
+ </style>
+ `;
+
+ var input00 = document.createElement("input");
+ input00.setAttribute("style", "background-color: red;");
+ input00.onfocus = focusLogger;
+ sr0.appendChild(input00);
+
+ var container01 = document.createElement("div");
+ container01.onfocus = focusLogger;
+ sr0.appendChild(container01);
+
+ var input010 = document.createElement("input");
+ input010.onfocus = focusLogger;
+ container01.appendChild(input010);
+
+ var input011 = document.createElement("input");
+ input011.onfocus = focusLogger;
+ container01.appendChild(input011);
+
+ var slot02 = document.createElement("slot");
+ slot02.onfocus = focusLogger;
+ sr0.appendChild(slot02);
+
+ var input020 = document.createElement("input");
+ input020.setAttribute("style", "display: block;");
+ input020.onfocus = focusLogger;
+ host0.appendChild(input020);
+
+ var input021 = document.createElement("input");
+ input021.setAttribute("style", "display: block;");
+ input021.onfocus = focusLogger;
+ host0.appendChild(input021);
+
+ var input1 = document.createElement("input");
+ input1.onfocus = focusLogger;
+ document.body.appendChild(input1);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, host0, "Should have focused shadow host element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input00, "Should have focused input element in shadow dom. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, container01, "Should have focused scrollable element in shadow dom. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input010, "Should have focused input element in shadow dom. (4)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input011, "Should have focused input element in shadow dom. (5)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, slot02, "Should have focused slot element in shadow dom. (6)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input020, "Should have focused input element in slot. (7)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input021, "Should have focused input element in slot. (8)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, input1, "Should have focused input element in light dom. (9)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input021, "Should have focused input element in slot. (10)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input020, "Should have focused input element in slot. (11)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, slot02, "Should have focused slot element in shadow dom. (12)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input011, "Should have focused input element in shadow dom. (13)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input010, "Should have focused input element in shadow dom. (14)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, container01, "Should have focused scrollable element in shadow dom. (15)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, input00, "Should have focused input element in shadow dom. (16)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ // focus is already on host
+ opener.is(sr0.activeElement, null,
+ "Focus should have left input element in shadow DOM. (7)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ host0.remove();
+ input1.remove();
+ }
+
+ // Bug 1604140
+ function testTabbingThroughScrollableShadowHost() {
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ let aboveFirstHost = document.createElement("div");
+ aboveFirstHost.tabIndex = 0;
+ aboveFirstHost.onfocus = focusLogger;
+ document.body.appendChild(aboveFirstHost);
+
+ let firstHost = document.createElement("div");
+ firstHost.style = "overflow: scroll";
+ document.body.appendChild(firstHost);
+
+ let firstShadow = firstHost.attachShadow({mode: "open"});
+ let divInFirstShadow = document.createElement("div");
+ divInFirstShadow.tabIndex = 0;
+ divInFirstShadow.onfocus = focusLogger;
+ firstShadow.appendChild(divInFirstShadow);
+
+ let aboveSecondHost = document.createElement("div");
+ aboveSecondHost.tabIndex = 0;
+ aboveSecondHost.onfocus = focusLogger;
+ document.body.appendChild(aboveSecondHost);
+
+ let secondHost = document.createElement("div");
+ secondHost.style = "overflow: scroll";
+ secondHost.tabIndex = 0;
+ secondHost.onfocus = focusLogger;
+ document.body.appendChild(secondHost);
+
+ let secondShadow = secondHost.attachShadow({mode: "open"});
+ let divInSecondShadow = document.createElement("div");
+ divInSecondShadow.tabIndex = 0;
+ divInSecondShadow.onfocus = focusLogger;
+ secondShadow.appendChild(divInSecondShadow);
+
+ let belowSecondHost = document.createElement("div");
+ belowSecondHost.tabIndex = 0;
+ belowSecondHost.onfocus = focusLogger;
+ document.body.appendChild(belowSecondHost);
+
+ document.body.offsetLeft;
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, aboveFirstHost, "Should have focused div above first host element. (1)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, divInFirstShadow, "Should have focused div in first shadow dom. (2)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, aboveSecondHost, "Should have focused div above second host element. (3)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, secondHost, "Should have focused second host element. (4)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, divInSecondShadow, "Should have focused div in second shadow dom. (5)");
+
+ synthesizeKey("KEY_Tab");
+ opener.is(lastFocusTarget, belowSecondHost, "Should have focused div below second host. (6)");
+
+ // Backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, divInSecondShadow, "Should have focused div in second shadow dom. (7)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ // focus is already on second host, so lastFocusTarget won't get updated.
+ opener.is(document.activeElement, secondHost, "Should have focused second host element. (8)");
+ opener.is(secondShadow.activeElement, null, "Focus should have left div in second shadow dom. (8)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, aboveSecondHost, "Should have focused div above second host element. (9)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, divInFirstShadow, "Should have focused div in first shadow dom. (10)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(lastFocusTarget, aboveFirstHost, "Should have focused div above first host element. (11)");
+
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild,
+ "body's first child should have focus.");
+
+ aboveFirstHost.remove();
+ firstHost.remove();
+ aboveSecondHost.remove();
+ secondHost.remove();
+ belowSecondHost.remove();
+ }
+
+ function testDeeplyNestedShadowTree() {
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus.");
+ var host1 = document.createElement("test-node");
+ var lastHost = host1;
+ for (var i = 0; i < 20; ++i) {
+ lastHost.appendChild(document.createElement("test-node"));
+ lastHost = lastHost.firstChild;
+ }
+
+ var input = document.createElement("input");
+ document.body.appendChild(host1);
+ document.body.appendChild(input);
+ document.body.offsetLeft;
+
+ // Test shadow tree which doesn't have anything tab-focusable.
+ host1.shadowRoot.querySelector("div").focus();
+ synthesizeKey("KEY_Tab");
+ is(document.activeElement, input, "Should have focused input element.");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus.");
+
+ // Same test but with focusable elements in the tree...
+ var input2 = document.createElement("input");
+ var host2 = host1.firstChild;
+ var host3 = host2.firstChild;
+ host2.insertBefore(input2, host3);
+ var input3 = document.createElement("input");
+ lastHost.appendChild(input3);
+ document.body.offsetLeft;
+ host3.shadowRoot.querySelector("div").focus();
+ synthesizeKey("KEY_Tab");
+ is(document.activeElement, input3, "Should have focused input3 element.");
+
+ // ...and backwards
+ host3.shadowRoot.querySelector("div").focus();
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ is(document.activeElement, input2, "Should have focused input2 element.");
+
+ // Remove elements added to body element.
+ host1.remove();
+ input.remove();
+
+ // Tests expect body.firstChild to have focus.
+ document.body.firstChild.focus();
+ }
+
+ // Bug 1558393
+ function testBackwardsTabbingWithSlotsWithoutFocusableContent() {
+ let first = document.createElement("div");
+ first.tabIndex = 0;
+ let host = document.createElement("div");
+ host.tabIndex = 0;
+ let second = document.createElement("div");
+ second.tabIndex = 0;
+ host.appendChild(document.createTextNode("foo"));
+ host.attachShadow({ mode: "open" }).innerHTML = `<slot></slot>`;
+
+ document.body.appendChild(first);
+ document.body.appendChild(host);
+ document.body.appendChild(second);
+ document.body.offsetLeft;
+
+ first.focus();
+ opener.is(document.activeElement, first, "First light div should have focus");
+ synthesizeKey("KEY_Tab");
+ opener.is(document.activeElement, host, "Host should be focused");
+ synthesizeKey("KEY_Tab");
+ opener.is(document.activeElement, second, "Second light div should be focused");
+
+ // Now backwards
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, host, "Focus should return to host");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ opener.is(document.activeElement, first, "Focus should return to first light div");
+
+ second.remove();
+ host.remove();
+ first.remove();
+ }
+
+ function runTest() {
+
+ testTabbingThroughShadowDOMWithTabIndexes();
+ testTabbingThroughSimpleShadowDOM();
+ testTabbingThroughNestedShadowDOM();
+ testTabbingThroughDisplayContentsHost();
+ testTabbingThroughLightDOMShadowDOMLightDOM();
+ testFocusableHost();
+ testShiftTabbingThroughFocusableHost();
+ testTabbingThroughNestedSlot();
+ testTabbingThroughSlotInLightDOM();
+ testTabbingThroughFocusableSlotInLightDOM();
+ testTabbingThroughScrollableShadowDOM();
+ testTabbingThroughScrollableShadowHost();
+ testDeeplyNestedShadowTree();
+ testBackwardsTabbingWithSlotsWithoutFocusableContent();
+
+ opener.didRunTests();
+ window.close();
+ }
+
+ function init() {
+ SimpleTest.waitForFocus(runTest);
+ }
+ </script>
+ <style>
+ </style>
+ <template id="template">
+ <div style="overflow: hidden">
+ <p tabindex="0" id="p1">component</p>
+ <p tabindex="0" id="p2">/component</p>
+ </div>
+ </template>
+ </head>
+ <body onload="init()">
+ </body>
+</html>
diff --git a/dom/base/test/file_general_document.html b/dom/base/test/file_general_document.html
new file mode 100644
index 0000000000..2539669de9
--- /dev/null
+++ b/dom/base/test/file_general_document.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>General document for testing</title>
+</head>
+<body>
+<p>Hello mochitest!</p>
+</body>
+</html>
diff --git a/dom/base/test/file_history_document_open.html b/dom/base/test/file_history_document_open.html
new file mode 100644
index 0000000000..b9f05f7c2c
--- /dev/null
+++ b/dom/base/test/file_history_document_open.html
@@ -0,0 +1 @@
+<script>function f() { history.length; } window.onload = function() { var func = window.f; document.open(); document.close(); parent.continueTest(func); }</script>
diff --git a/dom/base/test/file_htmlserializer_1.html b/dom/base/test/file_htmlserializer_1.html
new file mode 100644
index 0000000000..9576b5d7d6
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html><html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong> adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_bodyonly.html b/dom/base/test/file_htmlserializer_1_bodyonly.html
new file mode 100644
index 0000000000..848167c62a
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_bodyonly.html
@@ -0,0 +1,43 @@
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_format.html b/dom/base/test/file_htmlserializer_1_format.html
new file mode 100644
index 0000000000..09f80467e4
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_format.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+ </head>
+ <body>
+ <p>Hello world</p>
+ <p> Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+ adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis
+ ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent
+ taciti <span>sociosqu ad litora</span> torquent <a
+ href="file_htmlserializer_1_result1.html">per conubia</a>
+ nostra, per inceptos hymenaeos. </p>
+ <ul>
+ <li>Nam tellus massa,éàèçù</li>
+ <li> fringilla aliquam,</li>
+ <li> fermentum sit amet,</li>
+ <li>posuere ac,</li>
+ <li> est.</li>
+ </ul>
+ <div> Duis tristique egestas ligula. Mauris quis felis. </div>
+ <script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+ <ol>
+ <li>Fusce a ipsum</li>
+ <li> non lacus posuere aliquet.</li>
+ <li> Sed fermentum posuere nulla</li>
+ <li> Donec tempor.</li>
+ </ol>
+ Donec sollicitudin tortor
+ <!-- test on
+comments -->
+ <pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ ut gravida eros leo ut libero
+ <p></p>
+ <noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+ <p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus
+ aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+ </body>
+</html>
diff --git a/dom/base/test/file_htmlserializer_1_linebreak.html b/dom/base/test/file_htmlserializer_1_linebreak.html
new file mode 100644
index 0000000000..8194b8b415
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_linebreak.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_links.html b/dom/base/test/file_htmlserializer_1_links.html
new file mode 100644
index 0000000000..f0864c940c
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_links.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="http://mochi.test:8888/tests/dom/base/test/file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html>
diff --git a/dom/base/test/file_htmlserializer_1_nested_body.html b/dom/base/test/file_htmlserializer_1_nested_body.html
new file mode 100644
index 0000000000..94f67547e3
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_nested_body.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p><body><p>this is an other body element</p></body></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_no_body.html b/dom/base/test/file_htmlserializer_1_no_body.html
new file mode 100644
index 0000000000..9c749721b1
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_no_body.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_noflag.html b/dom/base/test/file_htmlserializer_1_noflag.html
new file mode 100644
index 0000000000..8194b8b415
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_noflag.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_noformatpre.html b/dom/base/test/file_htmlserializer_1_noformatpre.html
new file mode 100644
index 0000000000..aba95b62c8
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_noformatpre.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.
+
+ Cras quis
+
+ nisi at odio
+
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum,
+
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_raw.html b/dom/base/test/file_htmlserializer_1_raw.html
new file mode 100644
index 0000000000..c646f26963
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_raw.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong> adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_sibling_body.html b/dom/base/test/file_htmlserializer_1_sibling_body.html
new file mode 100644
index 0000000000..f533e6679a
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_sibling_body.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body><p>this is an other body element</p></body><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_sibling_body_only_body.html b/dom/base/test/file_htmlserializer_1_sibling_body_only_body.html
new file mode 100644
index 0000000000..97c1625156
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_sibling_body_only_body.html
@@ -0,0 +1,43 @@
+<body><p>this is an other body element</p></body><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_1_wrap.html b/dom/base/test/file_htmlserializer_1_wrap.html
new file mode 100644
index 0000000000..4552e9cba5
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_1_wrap.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="content-type"
+content="text/html; charset=UTF-8">
+ <title>Test for html serializer</title>
+
+</head><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu
+ ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per
+ conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script type="text/javascript">
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum
+posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br>
+ Cras quis<br>
+ nisi at odio<br>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros leo ut libero
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc & non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus
+aliquet lectus. Nunc vitae eros. Class aptent taciti</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_2.html b/dom/base/test/file_htmlserializer_2.html
new file mode 100644
index 0000000000..2156b1610c
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_2.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html><html><head><title>Test for html serializer with entities</title>
+</head><body>
+
+<p>The basic set is just &nbsp; &amp; &lt; &gt; &quot; for interoperability with older products that don't support &alpha; and friends.</p>
+
+<p>latin1 &iexcl; &cent; &pound; &curren; &yen; &brvbar; &sect; &uml; &copy; &ordf; &laquo; &not; &shy; &reg; &macr; &deg; &plusmn; &sup2; &sup3; &acute;
+&micro; &para; &middot; &cedil; &sup1; &ordm; &raquo; &frac14; &frac12; &frac34; &iquest; &Agrave; &Aacute; &Acirc; &Atilde; &Auml; &Aring; &AElig;
+&Ccedil; &Egrave; &Eacute; &Ecirc; &Euml; &Igrave; &Iacute; &Icirc; &Iuml; &ETH; &Ntilde; &Ograve; &Oacute; &Ocirc; &Otilde; &Ouml; &times; &Oslash;
+&Ugrave; &Uacute; &Ucirc; &Uuml; &Yacute; &THORN; &szlig; &agrave; &aacute; &acirc; &atilde; &auml; &aring; &aelig; &ccedil; &egrave; &eacute; &ecirc;
+&euml; &igrave; &iacute; &icirc; &iuml; &eth; &ntilde; &ograve; &oacute; &ocirc; &otilde; &ouml; &divide; &oslash; &ugrave; &uacute; &ucirc; &uuml; &yacute;
+&thorn; &yuml; </p>
+<p>symbols, math.. &fnof; &Alpha; &Beta; &Gamma; &Delta; &Epsilon; &Zeta; &Eta; &Theta; &Iota; &Kappa; &Lambda; &Mu; &Nu; &Xi; &Omicron; &Pi; &Rho; &Sigma; &Tau; &Upsilon;
+&Phi; &Chi; &Psi; &Omega; &alpha; &beta; &gamma; &delta; &epsilon; &zeta; &eta; &theta; &iota; &kappa; &lambda; &mu; &nu; &xi; &omicron; &pi; &rho; &sigmaf;
+&sigma; &tau; &upsilon; &phi; &chi; &psi; &omega; &thetasym; &upsih; &piv; &bull; &hellip; &prime; &Prime; &oline; &frasl; &weierp; &image; &real;
+&trade; &alefsym; &larr; &uarr; &rarr; &darr; &harr; &crarr; &lArr; &uArr; &rArr; &dArr; &hArr; &forall; &part; &exist; &empty; &nabla; &isin; &notin;
+&ni; &prod; &sum; &minus; &lowast; &radic; &prop; &infin; &ang; &and; &or; &cap; &cup; &int; &there4; &sim; &cong; &asymp; &ne; &equiv; &le; &ge;
+&sub; &sup; &nsub; &sube; &supe; &oplus; &otimes; &perp; &sdot; &lceil; &rceil; &lfloor; &rfloor; &loz; &spades; &clubs; &hearts; &diams;
+</p>
+<p> others
+&OElig; &oelig; &Scaron; &scaron; &Yuml; &circ; &tilde; &ensp; &emsp; &thinsp; &zwnj; &zwj; &lrm; &rlm;&ndash;&mdash; &lsquo; &rsquo;
+&sbquo;&ldquo; &rdquo; &bdquo; &dagger; &Dagger; &permil; &lsaquo; &rsaquo; &euro;
+</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_2_basic.html b/dom/base/test/file_htmlserializer_2_basic.html
new file mode 100644
index 0000000000..56ac95dfdd
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_2_basic.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset="><title>Test for html serializer with entities</title>
+</head><body>
+
+<p>The basic set is just &nbsp; &amp; &lt; &gt; " for interoperability with older products that don't support α and friends.</p>
+
+<p>latin1 ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´
+µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À à Â Ã Ä Å Æ
+Ç È É Ê Ë Ì à Î à à Ñ Ò Ó Ô Õ Ö × Ø
+Ù Ú Û Ü à Þ ß à á â ã ä å æ ç è é ê
+ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý
+þ ÿ </p>
+<p>symbols, math.. ƒ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ ΠΞ Ο Π Ρ Σ Τ Υ
+Φ Χ Ψ Ω α β γ δ ε ζ η θ ι κ λ μ ν ξ ο Ï€ Ï Ï‚
+σ τ υ φ χ ψ ω ϑ ϒ ϖ • … ′ ″ ‾ ℠℘ ℑ ℜ
+™ ℵ ↠↑ → ↓ ↔ ↵ ⇠⇑ ⇒ ⇓ ⇔ ∀ ∂ ∃ ∅ ∇ ∈ ∉
+∋ ∠∑ − ∗ √ ∠∞ ∠ ∧ ∨ ∩ ∪ ∫ ∴ ∼ ≅ ≈ ≠ ≡ ≤ ≥
+⊂ ⊃ ⊄ ⊆ ⊇ ⊕ ⊗ ⊥ ⋅ ⌈ ⌉ ⌊ ⌋ ◊ ♠ ♣ ♥ ♦
+</p>
+<p> others
+Å’ Å“ Å  Å¡ Ÿ ˆ Ëœ       ‌ †‎ â€â€“— ‘ ’
+‚“ †„ † ‡ ‰ ‹ › €
+</p></body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_ipv6.html b/dom/base/test/file_htmlserializer_ipv6.html
new file mode 100644
index 0000000000..298493e718
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_ipv6.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Testcase for IPv6 addresses</title>
+ <body>
+ <a href="http://[2001:4860:a003::68]/">Test</a>
+ </body></html> \ No newline at end of file
diff --git a/dom/base/test/file_htmlserializer_ipv6_out.html b/dom/base/test/file_htmlserializer_ipv6_out.html
new file mode 100644
index 0000000000..675a406d85
--- /dev/null
+++ b/dom/base/test/file_htmlserializer_ipv6_out.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Testcase for IPv6 addresses</title>
+ </head><body>
+ <a href="http://[2001:4860:a003::68]/">Test</a>
+ </body></html> \ No newline at end of file
diff --git a/dom/base/test/file_inline_script.html b/dom/base/test/file_inline_script.html
new file mode 100644
index 0000000000..838c70f946
--- /dev/null
+++ b/dom/base/test/file_inline_script.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script>window.scriptRan = true;</script>
+ <meta charset="utf-8">
+ <title></title>
+</head>
+<body>
+ <p>Hello Mochitest</p>
+</body>
+</html>
diff --git a/dom/base/test/file_inline_script.xhtml b/dom/base/test/file_inline_script.xhtml
new file mode 100644
index 0000000000..525daf29fe
--- /dev/null
+++ b/dom/base/test/file_inline_script.xhtml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <script>window.scriptRan = true;</script>
+ <title/>
+</head>
+<body>
+ <p>Hello Mochitest</p>
+</body>
+</html>
diff --git a/dom/base/test/file_js_cache.html b/dom/base/test/file_js_cache.html
new file mode 100644
index 0000000000..6feb94d872
--- /dev/null
+++ b/dom/base/test/file_js_cache.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Add a tag script to save the bytecode</title>
+</head>
+<body>
+ <script id="watchme" src="file_js_cache.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_js_cache.js b/dom/base/test/file_js_cache.js
new file mode 100644
index 0000000000..b9b966775c
--- /dev/null
+++ b/dom/base/test/file_js_cache.js
@@ -0,0 +1,5 @@
+function baz() {}
+function bar() {}
+function foo() { bar() }
+foo();
+
diff --git a/dom/base/test/file_js_cache_module.html b/dom/base/test/file_js_cache_module.html
new file mode 100644
index 0000000000..36d549c945
--- /dev/null
+++ b/dom/base/test/file_js_cache_module.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Load the script as a module</title>
+</head>
+<body>
+ <!-- crossorigin="use-credentials", because if we do an anonymous load that --
+ -- won't use the cache at all -->
+ <script id="watchme" src="file_js_cache.js" type="module"
+ crossorigin="use-credentials"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_js_cache_save_after_load.html b/dom/base/test/file_js_cache_save_after_load.html
new file mode 100644
index 0000000000..8a696c0026
--- /dev/null
+++ b/dom/base/test/file_js_cache_save_after_load.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Save the bytecode when all scripts are executed</title>
+</head>
+<body>
+ <script id="watchme" src="file_js_cache_save_after_load.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_js_cache_save_after_load.js b/dom/base/test/file_js_cache_save_after_load.js
new file mode 100644
index 0000000000..7f5a20b524
--- /dev/null
+++ b/dom/base/test/file_js_cache_save_after_load.js
@@ -0,0 +1,15 @@
+function send_ping() {
+ window.dispatchEvent(new Event("ping"));
+}
+send_ping(); // ping (=1)
+
+window.addEventListener("load", function () {
+ send_ping(); // ping (=2)
+
+ // Append a script which should call |foo|, before the encoding of this script
+ // bytecode.
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.innerText = "send_ping();"; // ping (=3)
+ document.head.appendChild(script);
+});
diff --git a/dom/base/test/file_js_cache_syntax_error.html b/dom/base/test/file_js_cache_syntax_error.html
new file mode 100644
index 0000000000..cc4a9b2daa
--- /dev/null
+++ b/dom/base/test/file_js_cache_syntax_error.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Do not save bytecode on compilation errors</title>
+</head>
+<body>
+ <script id="watchme" src="file_js_cache_syntax_error.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_js_cache_syntax_error.js b/dom/base/test/file_js_cache_syntax_error.js
new file mode 100644
index 0000000000..fcf587ae70
--- /dev/null
+++ b/dom/base/test/file_js_cache_syntax_error.js
@@ -0,0 +1 @@
+var // SyntaxError: missing variable name.
diff --git a/dom/base/test/file_js_cache_with_sri.html b/dom/base/test/file_js_cache_with_sri.html
new file mode 100644
index 0000000000..38ecb26984
--- /dev/null
+++ b/dom/base/test/file_js_cache_with_sri.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Add a tag script to save the bytecode</title>
+</head>
+<body>
+ <script id="watchme" src="file_js_cache.js"
+ integrity="sha384-8YSwN2ywq1SVThihWhj7uTVZ4UeIDwo3GgdPYnug+C+OS0oa6kH2IXBclwMaDJFb">
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_location_href_unknown_protocol.html b/dom/base/test/file_location_href_unknown_protocol.html
new file mode 100644
index 0000000000..10c994fbde
--- /dev/null
+++ b/dom/base/test/file_location_href_unknown_protocol.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<script>
+onbeforeunload = function() {
+ opener.onChildBeforeUnload();
+};
+onload = function() {
+ location.href = "this-protocol-is-unlikely-to-exist://foo";
+ setTimeout(function() {
+ opener.onChildLoadTimedOut();
+ }, 1000);
+};
+onunload = function() {
+ opener.onChildUnload();
+};
+</script>
diff --git a/dom/base/test/file_lock_orientation_with_pending_fullscreen.html b/dom/base/test/file_lock_orientation_with_pending_fullscreen.html
new file mode 100644
index 0000000000..07af0fc67d
--- /dev/null
+++ b/dom/base/test/file_lock_orientation_with_pending_fullscreen.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<script>
+const ok = window.parent.ok;
+const SpecialPowers = window.parent.SpecialPowers;
+
+async function runTest() {
+ SpecialPowers.wrap(document.documentElement).requestFullscreen();
+ const currentType = window.screen.orientation.type;
+ const lockPromise = window.screen.orientation.lock(currentType.startsWith("landscape") ? "portrait" : "landscape");
+ ok(true, "lock orientation doesn't throw error at this time");
+ // This document will be detached by "pending" message.
+ parent.postMessage("pending", "*");
+ await lockPromise;
+}
+</script>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/dom/base/test/file_messagemanager_unload.html b/dom/base/test/file_messagemanager_unload.html
new file mode 100644
index 0000000000..f01e60bae2
--- /dev/null
+++ b/dom/base/test/file_messagemanager_unload.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <iframe id="frame" src="empty.html"></iframe>
+ </body>
+</html>
diff --git a/dom/base/test/file_module_js_cache.html b/dom/base/test/file_module_js_cache.html
new file mode 100644
index 0000000000..ecf14903d9
--- /dev/null
+++ b/dom/base/test/file_module_js_cache.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Add a tag module script to save the bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_module_js_cache.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_module_js_cache.js b/dom/base/test/file_module_js_cache.js
new file mode 100644
index 0000000000..1b08386c81
--- /dev/null
+++ b/dom/base/test/file_module_js_cache.js
@@ -0,0 +1,6 @@
+function baz() {}
+function bar() {}
+function foo() {
+ bar();
+}
+foo();
diff --git a/dom/base/test/file_module_js_cache_no_module.html b/dom/base/test/file_module_js_cache_no_module.html
new file mode 100644
index 0000000000..fd5e23fb37
--- /dev/null
+++ b/dom/base/test/file_module_js_cache_no_module.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Load the module script as a regular script</title>
+</head>
+<body>
+ <script id="watchme" src="file_module_js_cache.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_module_js_cache_with_sri.html b/dom/base/test/file_module_js_cache_with_sri.html
new file mode 100644
index 0000000000..60b2ca4f7a
--- /dev/null
+++ b/dom/base/test/file_module_js_cache_with_sri.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Add a tag module script to save the bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_module_js_cache.js"
+ integrity="sha384-1eNjxPXQdMh9pdr8ctqxBCIqiAnwYWzCCIKpcEIWp2MjECaRYx5Iw1TC3p/dx/uj">
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_mozfiledataurl_img.jpg b/dom/base/test/file_mozfiledataurl_img.jpg
new file mode 100644
index 0000000000..dcd99b9670
--- /dev/null
+++ b/dom/base/test/file_mozfiledataurl_img.jpg
Binary files differ
diff --git a/dom/base/test/file_navigator_resolve_identity_xrays.xhtml b/dom/base/test/file_navigator_resolve_identity_xrays.xhtml
new file mode 100644
index 0000000000..bdce7c7b64
--- /dev/null
+++ b/dom/base/test/file_navigator_resolve_identity_xrays.xhtml
@@ -0,0 +1,29 @@
+<?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=985827
+-->
+<window title="Mozilla Bug 985827"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <iframe id="t"></iframe>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 985827 **/
+
+ addLoadEvent(function() {
+ var ok = parent.ok;
+ var is = parent.is;
+
+ var nav = document.getElementById("t").contentWindow.navigator;
+
+ ok(Cu.isXrayWrapper(nav), "Should have an Xray here");
+ });
+
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/file_receiveMessage.html b/dom/base/test/file_receiveMessage.html
new file mode 100644
index 0000000000..66f421270f
--- /dev/null
+++ b/dom/base/test/file_receiveMessage.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ window.onmessage = event => {
+ document.body.textContent = `${event.origin}|${event.data}`;
+ };
+ </script>
+</head>
+
+<body></body>
+</html>
+
diff --git a/dom/base/test/file_restrictedEventSource.sjs b/dom/base/test/file_restrictedEventSource.sjs
new file mode 100644
index 0000000000..b7ca11002a
--- /dev/null
+++ b/dom/base/test/file_restrictedEventSource.sjs
@@ -0,0 +1,69 @@
+function handleRequest(request, response) {
+ if (
+ (request.queryString == "test=user1_xhr" &&
+ request.hasHeader("Authorization") &&
+ request.getHeader("Authorization") == "Basic dXNlciAxOnBhc3N3b3JkIDE=") ||
+ (request.queryString == "test=user1_evtsrc" &&
+ request.hasHeader("Authorization") &&
+ request.getHeader("Authorization") == "Basic dXNlciAxOnBhc3N3b3JkIDE=")
+ ) {
+ response.setStatusLine(null, 200, "OK");
+ response.setHeader("Content-Type", "text/event-stream", false);
+ response.setHeader(
+ "Access-Control-Allow-Origin",
+ "http://mochi.test:8888",
+ false
+ );
+ response.setHeader("Access-Control-Allow-Credentials", "true", false);
+ response.setHeader("Cache-Control", "no-cache, must-revalidate", false);
+ if (request.queryString == "test=user1_xhr") {
+ response.setHeader("Set-Cookie", "test=5c", false);
+ }
+ response.write("event: message\ndata: 1\n\n");
+ } else if (
+ (request.queryString == "test=user2_xhr" &&
+ request.hasHeader("Authorization") &&
+ request.getHeader("Authorization") == "Basic dXNlciAyOnBhc3N3b3JkIDI=") ||
+ (request.queryString == "test=user2_evtsrc" &&
+ request.hasHeader("Authorization") &&
+ request.getHeader("Authorization") == "Basic dXNlciAyOnBhc3N3b3JkIDI=" &&
+ request.hasHeader("Cookie") &&
+ request.getHeader("Cookie") == "test=5d")
+ ) {
+ response.setStatusLine(null, 200, "OK");
+ response.setHeader("Content-Type", "text/event-stream", false);
+ response.setHeader(
+ "Access-Control-Allow-Origin",
+ "http://mochi.test:8888",
+ false
+ );
+ response.setHeader("Access-Control-Allow-Credentials", "true", false);
+ response.setHeader("Cache-Control", "no-cache, must-revalidate", false);
+ if (request.queryString == "test=user2_xhr") {
+ response.setHeader("Set-Cookie", "test=5d", false);
+ }
+ response.write("event: message\ndata: 1\n\n");
+ } else if (
+ request.queryString == "test=user1_xhr" ||
+ request.queryString == "test=user2_xhr"
+ ) {
+ response.setStatusLine(null, 401, "Unauthorized");
+ response.setHeader("WWW-Authenticate", 'basic realm="restricted"', false);
+ response.setHeader(
+ "Access-Control-Allow-Origin",
+ "http://mochi.test:8888",
+ false
+ );
+ response.setHeader("Access-Control-Allow-Credentials", "true", false);
+ response.write("Unauthorized");
+ } else {
+ response.setStatusLine(null, 403, "Forbidden");
+ response.setHeader(
+ "Access-Control-Allow-Origin",
+ "http://mochi.test:8888",
+ false
+ );
+ response.setHeader("Access-Control-Allow-Credentials", "true", false);
+ response.write("Forbidden");
+ }
+}
diff --git a/dom/base/test/file_sandbox_and_document_uri.html b/dom/base/test/file_sandbox_and_document_uri.html
new file mode 100644
index 0000000000..ac23cd1fec
--- /dev/null
+++ b/dom/base/test/file_sandbox_and_document_uri.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/ChromeTask.js"></script>
+ <script>
+ function test() {
+ location.hash = "foobar"
+ if (!document.documentURI.includes("#foobar")) {
+ opener.postMessage("Wrong documentURI", "*");
+ window.close();
+ } else {
+ ChromeTask.spawn(null, () => {
+ return {
+ documentURI: actorParent.documentURI.spec,
+ principalURI: actorParent.documentPrincipal.URI.spec
+ };
+ }).then((uriAndPrincipal) => {
+ if (!uriAndPrincipal.documentURI.includes("#foobar")) {
+ opener.postMessage("Wrong documentURI in the parent process", "*");
+ } else if (!uriAndPrincipal.principalURI.includes("moz-nullprincipal")) {
+ opener.postMessage("Wrong document principal in the parent process", "*");
+ } else {
+ opener.postMessage("done", "*");
+ }
+ window.close();
+ });
+ }
+ }
+ </script>
+ </head>
+ <body onload="setTimeout(test)">
+ </body>
+</html>
diff --git a/dom/base/test/file_script.js b/dom/base/test/file_script.js
new file mode 100644
index 0000000000..3e15525fa6
--- /dev/null
+++ b/dom/base/test/file_script.js
@@ -0,0 +1 @@
+window.scriptRan = true;
diff --git a/dom/base/test/file_script_module_dynamic_and_element.html b/dom/base/test/file_script_module_dynamic_and_element.html
new file mode 100644
index 0000000000..dce909fcf9
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_element.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_dynamic_and_element.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_dynamic_and_element.js b/dom/base/test/file_script_module_dynamic_and_element.js
new file mode 100644
index 0000000000..4f5c707a4c
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_element.js
@@ -0,0 +1,19 @@
+const { f } = await import(
+ "./file_script_module_dynamic_and_element_imported_1.js"
+);
+import { g } from "./file_script_module_dynamic_and_element_imported_2.js";
+import { h } from "./file_script_module_dynamic_and_element_imported_3.js";
+f();
+g();
+h();
+
+let script = document.createElement("script");
+script.id = "watchme2";
+script.setAttribute("type", "module");
+script.setAttribute(
+ "src",
+ "file_script_module_dynamic_and_element_imported_1.js"
+);
+document.body.appendChild(script);
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_dynamic_and_element_imported_1.js b/dom/base/test/file_script_module_dynamic_and_element_imported_1.js
new file mode 100644
index 0000000000..0be3913c65
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_element_imported_1.js
@@ -0,0 +1,6 @@
+import { g } from "./file_script_module_dynamic_and_element_imported_2.js";
+import { h } from "./file_script_module_dynamic_and_element_imported_3.js";
+g();
+h();
+
+export function f() {}
diff --git a/dom/base/test/file_script_module_dynamic_and_element_imported_2.js b/dom/base/test/file_script_module_dynamic_and_element_imported_2.js
new file mode 100644
index 0000000000..f75e8c9b21
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_element_imported_2.js
@@ -0,0 +1 @@
+export function g() {}
diff --git a/dom/base/test/file_script_module_dynamic_and_element_imported_3.js b/dom/base/test/file_script_module_dynamic_and_element_imported_3.js
new file mode 100644
index 0000000000..6b340b7588
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_element_imported_3.js
@@ -0,0 +1 @@
+export function h() {}
diff --git a/dom/base/test/file_script_module_dynamic_and_static.html b/dom/base/test/file_script_module_dynamic_and_static.html
new file mode 100644
index 0000000000..2a19772af1
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_static.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_dynamic_and_static.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_dynamic_and_static.js b/dom/base/test/file_script_module_dynamic_and_static.js
new file mode 100644
index 0000000000..3e2a50b7ab
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_static.js
@@ -0,0 +1,10 @@
+const { f } = await import(
+ "./file_script_module_dynamic_and_static_imported_1.js"
+);
+import { g } from "./file_script_module_dynamic_and_static_imported_2.js";
+import { h } from "./file_script_module_dynamic_and_static_imported_3.js";
+f();
+g();
+h();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_dynamic_and_static_imported_1.js b/dom/base/test/file_script_module_dynamic_and_static_imported_1.js
new file mode 100644
index 0000000000..671704ea17
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_static_imported_1.js
@@ -0,0 +1,4 @@
+import { h } from "./file_script_module_dynamic_and_static_imported_3.js";
+h();
+
+export function f() {}
diff --git a/dom/base/test/file_script_module_dynamic_and_static_imported_2.js b/dom/base/test/file_script_module_dynamic_and_static_imported_2.js
new file mode 100644
index 0000000000..e1a0050bce
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_static_imported_2.js
@@ -0,0 +1,4 @@
+import { f } from "./file_script_module_dynamic_and_static_imported_1.js";
+f();
+
+export function g() {}
diff --git a/dom/base/test/file_script_module_dynamic_and_static_imported_3.js b/dom/base/test/file_script_module_dynamic_and_static_imported_3.js
new file mode 100644
index 0000000000..6b340b7588
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_and_static_imported_3.js
@@ -0,0 +1 @@
+export function h() {}
diff --git a/dom/base/test/file_script_module_dynamic_import.html b/dom/base/test/file_script_module_dynamic_import.html
new file mode 100644
index 0000000000..574e7f8411
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_import.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_dynamic_import.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_dynamic_import.js b/dom/base/test/file_script_module_dynamic_import.js
new file mode 100644
index 0000000000..c0ae8cf5d2
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_import.js
@@ -0,0 +1,4 @@
+const { f } = await import("./file_script_module_dynamic_import_imported.js");
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_dynamic_import_imported.js b/dom/base/test/file_script_module_dynamic_import_imported.js
new file mode 100644
index 0000000000..8b38a11158
--- /dev/null
+++ b/dom/base/test/file_script_module_dynamic_import_imported.js
@@ -0,0 +1 @@
+export function f() {}
diff --git a/dom/base/test/file_script_module_element_and_dynamic.html b/dom/base/test/file_script_module_element_and_dynamic.html
new file mode 100644
index 0000000000..178e76d797
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_dynamic.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_element_and_dynamic_imported_1.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_element_and_dynamic.js b/dom/base/test/file_script_module_element_and_dynamic.js
new file mode 100644
index 0000000000..6bd59930bb
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_dynamic.js
@@ -0,0 +1,10 @@
+const { f } = await import(
+ "./file_script_module_element_and_dynamic_imported_1.js"
+);
+import { g } from "./file_script_module_element_and_dynamic_imported_2.js";
+import { h } from "./file_script_module_element_and_dynamic_imported_3.js";
+f();
+g();
+h();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_element_and_dynamic_imported_1.js b/dom/base/test/file_script_module_element_and_dynamic_imported_1.js
new file mode 100644
index 0000000000..d56c222120
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_dynamic_imported_1.js
@@ -0,0 +1,12 @@
+import { g } from "./file_script_module_element_and_dynamic_imported_2.js";
+import { h } from "./file_script_module_element_and_dynamic_imported_3.js";
+g();
+h();
+
+export function f() {}
+
+let script = document.createElement("script");
+script.id = "watchme2";
+script.setAttribute("type", "module");
+script.setAttribute("src", "file_script_module_element_and_dynamic.js");
+document.body.appendChild(script);
diff --git a/dom/base/test/file_script_module_element_and_dynamic_imported_2.js b/dom/base/test/file_script_module_element_and_dynamic_imported_2.js
new file mode 100644
index 0000000000..f75e8c9b21
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_dynamic_imported_2.js
@@ -0,0 +1 @@
+export function g() {}
diff --git a/dom/base/test/file_script_module_element_and_dynamic_imported_3.js b/dom/base/test/file_script_module_element_and_dynamic_imported_3.js
new file mode 100644
index 0000000000..6b340b7588
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_dynamic_imported_3.js
@@ -0,0 +1 @@
+export function h() {}
diff --git a/dom/base/test/file_script_module_element_and_import.html b/dom/base/test/file_script_module_element_and_import.html
new file mode 100644
index 0000000000..97d67f129e
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_import.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_element_and_import_imported_1.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_element_and_import.js b/dom/base/test/file_script_module_element_and_import.js
new file mode 100644
index 0000000000..18d0f57727
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_import.js
@@ -0,0 +1,8 @@
+import { f } from "./file_script_module_element_and_import_imported_1.js";
+import { g } from "./file_script_module_element_and_import_imported_2.js";
+import { h } from "./file_script_module_element_and_import_imported_3.js";
+f();
+g();
+h();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_element_and_import_imported_1.js b/dom/base/test/file_script_module_element_and_import_imported_1.js
new file mode 100644
index 0000000000..a257a40da9
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_import_imported_1.js
@@ -0,0 +1,12 @@
+import { g } from "./file_script_module_element_and_import_imported_2.js";
+import { h } from "./file_script_module_element_and_import_imported_3.js";
+g();
+h();
+
+export function f() {}
+
+let script = document.createElement("script");
+script.id = "watchme2";
+script.setAttribute("type", "module");
+script.setAttribute("src", "file_script_module_element_and_import.js");
+document.body.appendChild(script);
diff --git a/dom/base/test/file_script_module_element_and_import_imported_2.js b/dom/base/test/file_script_module_element_and_import_imported_2.js
new file mode 100644
index 0000000000..f75e8c9b21
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_import_imported_2.js
@@ -0,0 +1 @@
+export function g() {}
diff --git a/dom/base/test/file_script_module_element_and_import_imported_3.js b/dom/base/test/file_script_module_element_and_import_imported_3.js
new file mode 100644
index 0000000000..6b340b7588
--- /dev/null
+++ b/dom/base/test/file_script_module_element_and_import_imported_3.js
@@ -0,0 +1 @@
+export function h() {}
diff --git a/dom/base/test/file_script_module_frames_dynamic.html b/dom/base/test/file_script_module_frames_dynamic.html
new file mode 100644
index 0000000000..9f07e094fa
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_dynamic.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+ <script type="text/javascript">
+var loadFramePromiseResolve;
+var loadFramePromise = new Promise(r => {
+ loadFramePromiseResolve = r;
+});
+function onLoadFrameLoaded() {
+ loadFramePromiseResolve();
+}
+ </script>
+</head>
+<body>
+ <iframe id="save" name="save"
+ src="file_script_module_frames_dynamic_save.html"
+ width="50" height="50"></iframe>
+ <iframe id="load" name="load" onload="onLoadFrameLoaded()"
+ src="file_script_module_frames_dynamic_load.html"
+ width="50" height="50"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_dynamic_load.html b/dom/base/test/file_script_module_frames_dynamic_load.html
new file mode 100644
index 0000000000..eebb0fa36e
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_dynamic_load.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+</head>
+<body>
+ <script type="text/javascript" src="file_script_module_frames_relay.js"></script>
+ <script type="text/javascript">
+function doLoad() {
+ const script = document.createElement("script");
+ script.id = "watchme";
+ script.setAttribute("type", "module");
+ script.setAttribute("src", "file_script_module_frames_dynamic_load.js");
+ document.body.appendChild(script);
+}
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_dynamic_load.js b/dom/base/test/file_script_module_frames_dynamic_load.js
new file mode 100644
index 0000000000..ba14638f8c
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_dynamic_load.js
@@ -0,0 +1,4 @@
+const { f } = await import("./file_script_module_frames_dynamic_shared.js");
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_frames_dynamic_save.html b/dom/base/test/file_script_module_frames_dynamic_save.html
new file mode 100644
index 0000000000..64d9e01482
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_dynamic_save.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+</head>
+<body>
+ <script type="text/javascript" src="file_script_module_frames_relay.js"></script>
+ <script type="text/javascript">
+// Dynamically insert the script element so that the load doesn't happen
+// before the event relay handler is set up.
+const script = document.createElement("script");
+script.id = "watchme";
+script.setAttribute("type", "module");
+script.setAttribute("src", "file_script_module_frames_dynamic_save.js");
+document.body.appendChild(script);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_dynamic_save.js b/dom/base/test/file_script_module_frames_dynamic_save.js
new file mode 100644
index 0000000000..ba14638f8c
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_dynamic_save.js
@@ -0,0 +1,4 @@
+const { f } = await import("./file_script_module_frames_dynamic_shared.js");
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_frames_dynamic_shared.js b/dom/base/test/file_script_module_frames_dynamic_shared.js
new file mode 100644
index 0000000000..8b38a11158
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_dynamic_shared.js
@@ -0,0 +1 @@
+export function f() {}
diff --git a/dom/base/test/file_script_module_frames_element.html b/dom/base/test/file_script_module_frames_element.html
new file mode 100644
index 0000000000..aec8dfa5f0
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_element.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+ <script type="text/javascript">
+var loadFramePromiseResolve;
+var loadFramePromise = new Promise(r => {
+ loadFramePromiseResolve = r;
+});
+function onLoadFrameLoaded() {
+ loadFramePromiseResolve();
+}
+ </script>
+</head>
+<body>
+ <iframe id="save" name="save"
+ src="file_script_module_frames_element_save.html"
+ width="50" height="50"></iframe>
+ <iframe id="load" name="load" onload="onLoadFrameLoaded()"
+ src="file_script_module_frames_element_load.html"
+ width="50" height="50"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_element_load.html b/dom/base/test/file_script_module_frames_element_load.html
new file mode 100644
index 0000000000..940d9ad599
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_element_load.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+</head>
+<body>
+ <script type="text/javascript" src="file_script_module_frames_relay.js"></script>
+ <script type="text/javascript">
+function doLoad() {
+ const script = document.createElement("script");
+ script.id = "watchme";
+ script.setAttribute("type", "module");
+ script.setAttribute("src", "file_script_module_frames_element_shared.js");
+ document.body.appendChild(script);
+}
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_element_save.html b/dom/base/test/file_script_module_frames_element_save.html
new file mode 100644
index 0000000000..b665416676
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_element_save.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+</head>
+<body>
+ <script type="text/javascript" src="file_script_module_frames_relay.js"></script>
+ <script type="text/javascript">
+// Dynamically insert the script element so that the load doesn't happen
+// before the event relay handler is set up.
+const script = document.createElement("script");
+script.id = "watchme";
+script.setAttribute("type", "module");
+script.setAttribute("src", "file_script_module_frames_element_shared.js");
+document.body.appendChild(script);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_element_shared.js b/dom/base/test/file_script_module_frames_element_shared.js
new file mode 100644
index 0000000000..741b76cd09
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_element_shared.js
@@ -0,0 +1 @@
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_frames_import.html b/dom/base/test/file_script_module_frames_import.html
new file mode 100644
index 0000000000..a71d372724
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_import.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+ <script type="text/javascript">
+var loadFramePromiseResolve;
+var loadFramePromise = new Promise(r => {
+ loadFramePromiseResolve = r;
+});
+function onLoadFrameLoaded() {
+ loadFramePromiseResolve();
+}
+ </script>
+</head>
+<body>
+ <iframe id="save" name="save"
+ src="file_script_module_frames_import_save.html"
+ width="50" height="50"></iframe>
+ <iframe id="load" name="load" onload="onLoadFrameLoaded()"
+ src="file_script_module_frames_import_load.html"
+ width="50" height="50"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_import_load.html b/dom/base/test/file_script_module_frames_import_load.html
new file mode 100644
index 0000000000..d340e6c040
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_import_load.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+</head>
+<body>
+ <script type="text/javascript" src="file_script_module_frames_relay.js"></script>
+ <script type="text/javascript">
+function doLoad() {
+ const script = document.createElement("script");
+ script.id = "watchme";
+ script.setAttribute("type", "module");
+ script.setAttribute("src", "file_script_module_frames_import_load.js");
+ document.body.appendChild(script);
+}
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_import_load.js b/dom/base/test/file_script_module_frames_import_load.js
new file mode 100644
index 0000000000..3bae471015
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_import_load.js
@@ -0,0 +1,4 @@
+import { f } from "./file_script_module_frames_import_shared.js";
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_frames_import_save.html b/dom/base/test/file_script_module_frames_import_save.html
new file mode 100644
index 0000000000..532745d444
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_import_save.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode across iframe</title>
+</head>
+<body>
+ <script type="text/javascript" src="file_script_module_frames_relay.js"></script>
+ <script type="text/javascript">
+// Dynamically insert the script element so that the load doesn't happen
+// before the event relay handler is set up.
+const script = document.createElement("script");
+script.id = "watchme";
+script.setAttribute("type", "module");
+script.setAttribute("src", "file_script_module_frames_import_save.js");
+document.body.appendChild(script);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_frames_import_save.js b/dom/base/test/file_script_module_frames_import_save.js
new file mode 100644
index 0000000000..3bae471015
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_import_save.js
@@ -0,0 +1,4 @@
+import { f } from "./file_script_module_frames_import_shared.js";
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_frames_import_shared.js b/dom/base/test/file_script_module_frames_import_shared.js
new file mode 100644
index 0000000000..8b38a11158
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_import_shared.js
@@ -0,0 +1 @@
+export function f() {}
diff --git a/dom/base/test/file_script_module_frames_relay.js b/dom/base/test/file_script_module_frames_relay.js
new file mode 100644
index 0000000000..141f202962
--- /dev/null
+++ b/dom/base/test/file_script_module_frames_relay.js
@@ -0,0 +1,22 @@
+function relay(event) {
+ if (event.type != "test_evaluated") {
+ if (!/^watchme/.test(event.target.id)) {
+ return;
+ }
+ }
+
+ const type = `${window.name}_${event.type}`;
+
+ window.parent.dispatchEvent(new window.parent.Event(type));
+}
+
+window.addEventListener("scriptloader_load_source", relay);
+window.addEventListener("scriptloader_load_bytecode", relay);
+window.addEventListener("scriptloader_execute", relay);
+window.addEventListener("scriptloader_evaluate_module", relay);
+window.addEventListener("scriptloader_encode", relay);
+window.addEventListener("scriptloader_no_encode", relay);
+window.addEventListener("scriptloader_bytecode_saved", relay);
+window.addEventListener("scriptloader_bytecode_failed", relay);
+window.addEventListener("scriptloader_fallback", relay);
+window.addEventListener("test_evaluated", relay);
diff --git a/dom/base/test/file_script_module_import.html b/dom/base/test/file_script_module_import.html
new file mode 100644
index 0000000000..f298586da7
--- /dev/null
+++ b/dom/base/test/file_script_module_import.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_import.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_import.js b/dom/base/test/file_script_module_import.js
new file mode 100644
index 0000000000..d0c92afc66
--- /dev/null
+++ b/dom/base/test/file_script_module_import.js
@@ -0,0 +1,4 @@
+import { f } from "./file_script_module_import_imported.js";
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_import_and_element.html b/dom/base/test/file_script_module_import_and_element.html
new file mode 100644
index 0000000000..de5754eab2
--- /dev/null
+++ b/dom/base/test/file_script_module_import_and_element.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_import_and_element.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_import_and_element.js b/dom/base/test/file_script_module_import_and_element.js
new file mode 100644
index 0000000000..685d0199b2
--- /dev/null
+++ b/dom/base/test/file_script_module_import_and_element.js
@@ -0,0 +1,17 @@
+import { f } from "./file_script_module_import_and_element_imported_1.js";
+import { g } from "./file_script_module_import_and_element_imported_2.js";
+import { h } from "./file_script_module_import_and_element_imported_3.js";
+f();
+g();
+h();
+
+let script = document.createElement("script");
+script.id = "watchme2";
+script.setAttribute("type", "module");
+script.setAttribute(
+ "src",
+ "file_script_module_import_and_element_imported_1.js"
+);
+document.body.appendChild(script);
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_import_and_element_imported_1.js b/dom/base/test/file_script_module_import_and_element_imported_1.js
new file mode 100644
index 0000000000..4413bfbf85
--- /dev/null
+++ b/dom/base/test/file_script_module_import_and_element_imported_1.js
@@ -0,0 +1,6 @@
+import { g } from "./file_script_module_import_and_element_imported_2.js";
+import { h } from "./file_script_module_import_and_element_imported_3.js";
+g();
+h();
+
+export function f() {}
diff --git a/dom/base/test/file_script_module_import_and_element_imported_2.js b/dom/base/test/file_script_module_import_and_element_imported_2.js
new file mode 100644
index 0000000000..f75e8c9b21
--- /dev/null
+++ b/dom/base/test/file_script_module_import_and_element_imported_2.js
@@ -0,0 +1 @@
+export function g() {}
diff --git a/dom/base/test/file_script_module_import_and_element_imported_3.js b/dom/base/test/file_script_module_import_and_element_imported_3.js
new file mode 100644
index 0000000000..6b340b7588
--- /dev/null
+++ b/dom/base/test/file_script_module_import_and_element_imported_3.js
@@ -0,0 +1 @@
+export function h() {}
diff --git a/dom/base/test/file_script_module_import_imported.js b/dom/base/test/file_script_module_import_imported.js
new file mode 100644
index 0000000000..8b38a11158
--- /dev/null
+++ b/dom/base/test/file_script_module_import_imported.js
@@ -0,0 +1 @@
+export function f() {}
diff --git a/dom/base/test/file_script_module_import_multi.html b/dom/base/test/file_script_module_import_multi.html
new file mode 100644
index 0000000000..5636bd0f2d
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_import_multi.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_import_multi.js b/dom/base/test/file_script_module_import_multi.js
new file mode 100644
index 0000000000..54d7855d64
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi.js
@@ -0,0 +1,6 @@
+import { f } from "./file_script_module_import_multi_imported_once.js";
+import { g } from "./file_script_module_import_multi_imported_twice.js";
+f();
+g();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_import_multi_elems.html b/dom/base/test/file_script_module_import_multi_elems.html
new file mode 100644
index 0000000000..42edd06c52
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_elems.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_import_multi_elems_1.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_import_multi_elems_1.js b/dom/base/test/file_script_module_import_multi_elems_1.js
new file mode 100644
index 0000000000..11648d3d1a
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_elems_1.js
@@ -0,0 +1,14 @@
+import { f } from "./file_script_module_import_multi_elems_imported_once_1.js";
+import { h } from "./file_script_module_import_multi_elems_imported_twice.js";
+f();
+h();
+
+// Dynamically insert the element after loading all source, so that
+// the module import doesn't race.
+const script = document.createElement("script");
+script.id = "watchme2";
+script.setAttribute("type", "module");
+script.setAttribute("src", "file_script_module_import_multi_elems_2.js");
+document.body.appendChild(script);
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_import_multi_elems_2.js b/dom/base/test/file_script_module_import_multi_elems_2.js
new file mode 100644
index 0000000000..062c263fc4
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_elems_2.js
@@ -0,0 +1,6 @@
+import { g } from "./file_script_module_import_multi_elems_imported_once_2.js";
+import { h } from "./file_script_module_import_multi_elems_imported_twice.js";
+g();
+h();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_import_multi_elems_imported_once_1.js b/dom/base/test/file_script_module_import_multi_elems_imported_once_1.js
new file mode 100644
index 0000000000..8b38a11158
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_elems_imported_once_1.js
@@ -0,0 +1 @@
+export function f() {}
diff --git a/dom/base/test/file_script_module_import_multi_elems_imported_once_2.js b/dom/base/test/file_script_module_import_multi_elems_imported_once_2.js
new file mode 100644
index 0000000000..f75e8c9b21
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_elems_imported_once_2.js
@@ -0,0 +1 @@
+export function g() {}
diff --git a/dom/base/test/file_script_module_import_multi_elems_imported_once_3.js b/dom/base/test/file_script_module_import_multi_elems_imported_once_3.js
new file mode 100644
index 0000000000..411595cafc
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_elems_imported_once_3.js
@@ -0,0 +1 @@
+export function i() {}
diff --git a/dom/base/test/file_script_module_import_multi_elems_imported_twice.js b/dom/base/test/file_script_module_import_multi_elems_imported_twice.js
new file mode 100644
index 0000000000..fd0ddd25b4
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_elems_imported_twice.js
@@ -0,0 +1,3 @@
+import { i } from "./file_script_module_import_multi_elems_imported_once_3.js";
+i();
+export function h() {}
diff --git a/dom/base/test/file_script_module_import_multi_imported_once.js b/dom/base/test/file_script_module_import_multi_imported_once.js
new file mode 100644
index 0000000000..448c6641e5
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_imported_once.js
@@ -0,0 +1,4 @@
+import { g } from "./file_script_module_import_multi_imported_twice.js";
+g();
+
+export function f() {}
diff --git a/dom/base/test/file_script_module_import_multi_imported_twice.js b/dom/base/test/file_script_module_import_multi_imported_twice.js
new file mode 100644
index 0000000000..f75e8c9b21
--- /dev/null
+++ b/dom/base/test/file_script_module_import_multi_imported_twice.js
@@ -0,0 +1 @@
+export function g() {}
diff --git a/dom/base/test/file_script_module_single.html b/dom/base/test/file_script_module_single.html
new file mode 100644
index 0000000000..ec2c6f217c
--- /dev/null
+++ b/dom/base/test/file_script_module_single.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_single.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_single.js b/dom/base/test/file_script_module_single.js
new file mode 100644
index 0000000000..9a5745f516
--- /dev/null
+++ b/dom/base/test/file_script_module_single.js
@@ -0,0 +1,8 @@
+function baz() {}
+function bar() {}
+function foo() {
+ bar();
+}
+foo();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_basic.html b/dom/base/test/file_script_module_sri_basic.html
new file mode 100644
index 0000000000..743bcafbc7
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_basic.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_basic.js"
+ integrity="sha384-pZxhwO9umoHSuKzSRL6hi9YhRb70RfGdRnchu/zp5gbUCOC/x7NAWUPxxuv0DJoZ"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_basic.js b/dom/base/test/file_script_module_sri_basic.js
new file mode 100644
index 0000000000..741b76cd09
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_basic.js
@@ -0,0 +1 @@
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_basic_prep.html b/dom/base/test/file_script_module_sri_basic_prep.html
new file mode 100644
index 0000000000..743bcafbc7
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_basic_prep.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_basic.js"
+ integrity="sha384-pZxhwO9umoHSuKzSRL6hi9YhRb70RfGdRnchu/zp5gbUCOC/x7NAWUPxxuv0DJoZ"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem.html b/dom/base/test/file_script_module_sri_dynamic_elem.html
new file mode 100644
index 0000000000..a340f5f612
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_sri_dynamic_elem.js"></script>
+ <script id="watchme2" type="module" src="file_script_module_sri_dynamic_elem_imported.js"
+ integrity="sha384-3XSIfAj4/GALfWzL3T89+t3eaLIY59g8IWz1qq59xKnEW3aGd4cz7XvdcYqoK2+J"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem.js b/dom/base/test/file_script_module_sri_dynamic_elem.js
new file mode 100644
index 0000000000..b68c9bb80c
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem.js
@@ -0,0 +1,4 @@
+const { f } = await import("./file_script_module_sri_dynamic_elem_imported.js");
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem_imported.js b/dom/base/test/file_script_module_sri_dynamic_elem_imported.js
new file mode 100644
index 0000000000..bf624148c0
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem_imported.js
@@ -0,0 +1,3 @@
+export function f() {}
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem_nopreload.html b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload.html
new file mode 100644
index 0000000000..3f0a5f8c7b
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_dynamic_elem_nopreload.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem_nopreload.js b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload.js
new file mode 100644
index 0000000000..5139b0c34d
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload.js
@@ -0,0 +1,20 @@
+const { f } = await import(
+ "./file_script_module_sri_dynamic_elem_nopreload_imported.js"
+);
+f();
+
+// Dynamically insert the script element in order to suppress preload.
+const script = document.createElement("script");
+script.id = "watchme2";
+script.setAttribute("type", "module");
+script.setAttribute(
+ "src",
+ "file_script_module_sri_dynamic_elem_nopreload_imported.js"
+);
+script.setAttribute(
+ "integrity",
+ "sha384-3XSIfAj4/GALfWzL3T89+t3eaLIY59g8IWz1qq59xKnEW3aGd4cz7XvdcYqoK2+J"
+);
+document.body.appendChild(script);
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem_nopreload_imported.js b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload_imported.js
new file mode 100644
index 0000000000..bf624148c0
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload_imported.js
@@ -0,0 +1,3 @@
+export function f() {}
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem_nopreload_prep.html b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload_prep.html
new file mode 100644
index 0000000000..da70674200
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem_nopreload_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_dynamic_elem_nopreload_imported.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_dynamic_elem_prep.html b/dom/base/test/file_script_module_sri_dynamic_elem_prep.html
new file mode 100644
index 0000000000..598e8519fa
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_dynamic_elem_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_dynamic_elem_imported.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_dynamic.html b/dom/base/test/file_script_module_sri_elem_dynamic.html
new file mode 100644
index 0000000000..00741ca010
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_dynamic.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_sri_elem_dynamic_imported.js"
+ integrity="sha384-3XSIfAj4/GALfWzL3T89+t3eaLIY59g8IWz1qq59xKnEW3aGd4cz7XvdcYqoK2+J"></script>
+ <script id="watchme2" type="module" src="file_script_module_sri_elem_dynamic.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_dynamic.js b/dom/base/test/file_script_module_sri_elem_dynamic.js
new file mode 100644
index 0000000000..597038a066
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_dynamic.js
@@ -0,0 +1,4 @@
+const { f } = await import("./file_script_module_sri_elem_dynamic_imported.js");
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_elem_dynamic_imported.js b/dom/base/test/file_script_module_sri_elem_dynamic_imported.js
new file mode 100644
index 0000000000..bf624148c0
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_dynamic_imported.js
@@ -0,0 +1,3 @@
+export function f() {}
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_elem_dynamic_prep.html b/dom/base/test/file_script_module_sri_elem_dynamic_prep.html
new file mode 100644
index 0000000000..607fc0634f
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_dynamic_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_elem_dynamic_imported.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_elem_1.html b/dom/base/test/file_script_module_sri_elem_elem_1.html
new file mode 100644
index 0000000000..38312d7245
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_elem_1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_sri_elem_elem_1.js"></script>
+ <script id="watchme2" type="module" src="file_script_module_sri_elem_elem_1.js"
+ integrity="sha384-pZxhwO9umoHSuKzSRL6hi9YhRb70RfGdRnchu/zp5gbUCOC/x7NAWUPxxuv0DJoZ"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_elem_1.js b/dom/base/test/file_script_module_sri_elem_elem_1.js
new file mode 100644
index 0000000000..741b76cd09
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_elem_1.js
@@ -0,0 +1 @@
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_elem_elem_1_prep.html b/dom/base/test/file_script_module_sri_elem_elem_1_prep.html
new file mode 100644
index 0000000000..4617920deb
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_elem_1_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_elem_elem_1.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_elem_2.html b/dom/base/test/file_script_module_sri_elem_elem_2.html
new file mode 100644
index 0000000000..b39d018d8e
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_elem_2.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_sri_elem_elem_2.js"
+ integrity="sha384-pZxhwO9umoHSuKzSRL6hi9YhRb70RfGdRnchu/zp5gbUCOC/x7NAWUPxxuv0DJoZ"></script>
+ <script id="watchme2" type="module" src="file_script_module_sri_elem_elem_2.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_elem_2.js b/dom/base/test/file_script_module_sri_elem_elem_2.js
new file mode 100644
index 0000000000..741b76cd09
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_elem_2.js
@@ -0,0 +1 @@
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_elem_elem_2_prep.html b/dom/base/test/file_script_module_sri_elem_elem_2_prep.html
new file mode 100644
index 0000000000..600b7607cb
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_elem_2_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_elem_elem_2.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_import.html b/dom/base/test/file_script_module_sri_elem_import.html
new file mode 100644
index 0000000000..22e2712f21
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_import.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_sri_elem_import_imported.js"
+ integrity="sha384-3XSIfAj4/GALfWzL3T89+t3eaLIY59g8IWz1qq59xKnEW3aGd4cz7XvdcYqoK2+J"></script>
+ <script id="watchme2" type="module" src="file_script_module_sri_elem_import.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_elem_import.js b/dom/base/test/file_script_module_sri_elem_import.js
new file mode 100644
index 0000000000..5ecd8e4704
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_import.js
@@ -0,0 +1,4 @@
+import { f } from "./file_script_module_sri_elem_import_imported.js";
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_elem_import_imported.js b/dom/base/test/file_script_module_sri_elem_import_imported.js
new file mode 100644
index 0000000000..bf624148c0
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_import_imported.js
@@ -0,0 +1,3 @@
+export function f() {}
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_elem_import_prep.html b/dom/base/test/file_script_module_sri_elem_import_prep.html
new file mode 100644
index 0000000000..3b23ab7f3f
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_elem_import_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_elem_import_imported.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_fallback.html b/dom/base/test/file_script_module_sri_fallback.html
new file mode 100644
index 0000000000..5d54141816
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_fallback.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_fallback.js"
+ integrity="sha384-pZxhwO9umoHSuKzSRL6hi9YhRb70RfGdRnchu/zp5gbUCOC/x7NAWUPxxuv0DJoZ"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_fallback.js b/dom/base/test/file_script_module_sri_fallback.js
new file mode 100644
index 0000000000..741b76cd09
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_fallback.js
@@ -0,0 +1 @@
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_fallback_failure.html b/dom/base/test/file_script_module_sri_fallback_failure.html
new file mode 100644
index 0000000000..01eb0028f5
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_fallback_failure.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_fallback_failure.js"
+ integrity="sha384-wronghash"></script>
+ <script type="text/javascript">
+// The above script isn't evaluated because of wrong integrity.
+window.dispatchEvent(new Event("test_evaluated"));
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_fallback_failure.js b/dom/base/test/file_script_module_sri_fallback_failure.js
new file mode 100644
index 0000000000..741b76cd09
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_fallback_failure.js
@@ -0,0 +1 @@
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_fallback_failure_prep.html b/dom/base/test/file_script_module_sri_fallback_failure_prep.html
new file mode 100644
index 0000000000..a66b18dff0
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_fallback_failure_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_fallback_failure.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_fallback_prep.html b/dom/base/test/file_script_module_sri_fallback_prep.html
new file mode 100644
index 0000000000..dd1b6a0cc5
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_fallback_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_fallback.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_import_elem.html b/dom/base/test/file_script_module_sri_import_elem.html
new file mode 100644
index 0000000000..e37c05ac49
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme1" type="module" src="file_script_module_sri_import_elem.js"></script>
+ <script id="watchme2" type="module" src="file_script_module_sri_import_elem_imported.js"
+ integrity="sha384-3XSIfAj4/GALfWzL3T89+t3eaLIY59g8IWz1qq59xKnEW3aGd4cz7XvdcYqoK2+J"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_import_elem.js b/dom/base/test/file_script_module_sri_import_elem.js
new file mode 100644
index 0000000000..36c43f4d58
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem.js
@@ -0,0 +1,4 @@
+import { f } from "./file_script_module_sri_import_elem_imported.js";
+f();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_import_elem_imported.js b/dom/base/test/file_script_module_sri_import_elem_imported.js
new file mode 100644
index 0000000000..bf624148c0
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem_imported.js
@@ -0,0 +1,3 @@
+export function f() {}
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_import_elem_nopreload.html b/dom/base/test/file_script_module_sri_import_elem_nopreload.html
new file mode 100644
index 0000000000..5321288e33
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem_nopreload.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body onload="onLoad()">
+ <script id="watchme" type="module" src="file_script_module_sri_import_elem_nopreload.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_import_elem_nopreload.js b/dom/base/test/file_script_module_sri_import_elem_nopreload.js
new file mode 100644
index 0000000000..21606f7a8c
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem_nopreload.js
@@ -0,0 +1,18 @@
+import { f } from "./file_script_module_sri_import_elem_nopreload_imported.js";
+f();
+
+// Dynamically insert the script element in order to suppress preload.
+const script = document.createElement("script");
+script.id = "watchme2";
+script.setAttribute("type", "module");
+script.setAttribute(
+ "src",
+ "file_script_module_sri_import_elem_nopreload_imported.js"
+);
+script.setAttribute(
+ "integrity",
+ "sha384-3XSIfAj4/GALfWzL3T89+t3eaLIY59g8IWz1qq59xKnEW3aGd4cz7XvdcYqoK2+J"
+);
+document.body.appendChild(script);
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_import_elem_nopreload_imported.js b/dom/base/test/file_script_module_sri_import_elem_nopreload_imported.js
new file mode 100644
index 0000000000..bf624148c0
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem_nopreload_imported.js
@@ -0,0 +1,3 @@
+export function f() {}
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_sri_import_elem_nopreload_prep.html b/dom/base/test/file_script_module_sri_import_elem_nopreload_prep.html
new file mode 100644
index 0000000000..7fa9b011f8
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem_nopreload_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_import_elem_nopreload_imported.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_sri_import_elem_prep.html b/dom/base/test/file_script_module_sri_import_elem_prep.html
new file mode 100644
index 0000000000..5abdb1d16d
--- /dev/null
+++ b/dom/base/test/file_script_module_sri_import_elem_prep.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode fallback</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_sri_import_elem_imported.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_static_and_dynamic.html b/dom/base/test/file_script_module_static_and_dynamic.html
new file mode 100644
index 0000000000..ae614c85c1
--- /dev/null
+++ b/dom/base/test/file_script_module_static_and_dynamic.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test module script bytecode</title>
+</head>
+<body>
+ <script id="watchme" type="module" src="file_script_module_static_and_dynamic.js"></script>
+</body>
+</html>
diff --git a/dom/base/test/file_script_module_static_and_dynamic.js b/dom/base/test/file_script_module_static_and_dynamic.js
new file mode 100644
index 0000000000..60766106af
--- /dev/null
+++ b/dom/base/test/file_script_module_static_and_dynamic.js
@@ -0,0 +1,8 @@
+import { f } from "./file_script_module_static_and_dynamic_imported_1.js";
+import { g } from "./file_script_module_static_and_dynamic_imported_2.js";
+import { h } from "./file_script_module_static_and_dynamic_imported_3.js";
+f();
+g();
+h();
+
+window.dispatchEvent(new Event("test_evaluated"));
diff --git a/dom/base/test/file_script_module_static_and_dynamic_imported_1.js b/dom/base/test/file_script_module_static_and_dynamic_imported_1.js
new file mode 100644
index 0000000000..420667f36f
--- /dev/null
+++ b/dom/base/test/file_script_module_static_and_dynamic_imported_1.js
@@ -0,0 +1,4 @@
+import { h } from "./file_script_module_static_and_dynamic_imported_3.js";
+h();
+
+export function f() {}
diff --git a/dom/base/test/file_script_module_static_and_dynamic_imported_2.js b/dom/base/test/file_script_module_static_and_dynamic_imported_2.js
new file mode 100644
index 0000000000..c171417531
--- /dev/null
+++ b/dom/base/test/file_script_module_static_and_dynamic_imported_2.js
@@ -0,0 +1,6 @@
+const { f } = await import(
+ "./file_script_module_static_and_dynamic_imported_1.js"
+);
+f();
+
+export function g() {}
diff --git a/dom/base/test/file_script_module_static_and_dynamic_imported_3.js b/dom/base/test/file_script_module_static_and_dynamic_imported_3.js
new file mode 100644
index 0000000000..6b340b7588
--- /dev/null
+++ b/dom/base/test/file_script_module_static_and_dynamic_imported_3.js
@@ -0,0 +1 @@
+export function h() {}
diff --git a/dom/base/test/file_serializer_noscript.html b/dom/base/test/file_serializer_noscript.html
new file mode 100644
index 0000000000..440baf036c
--- /dev/null
+++ b/dom/base/test/file_serializer_noscript.html
@@ -0,0 +1 @@
+<body><noscript>&lt;/noscript&gt;<img></noscript></body>
diff --git a/dom/base/test/file_setname.html b/dom/base/test/file_setname.html
new file mode 100644
index 0000000000..0830feb53a
--- /dev/null
+++ b/dom/base/test/file_setname.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script>
+ window.name = location.search.substring(1);
+ </script>
+ </head>
+</html>
diff --git a/dom/base/test/file_settimeout_inner.html b/dom/base/test/file_settimeout_inner.html
new file mode 100644
index 0000000000..cfc66dfffb
--- /dev/null
+++ b/dom/base/test/file_settimeout_inner.html
@@ -0,0 +1 @@
+<script>window.onload = function runTest1() { document.open(); setTimeout('parent.test1Done();'); document.close(); }</script>
diff --git a/dom/base/test/file_suppressed_events_and_scrolling.html b/dom/base/test/file_suppressed_events_and_scrolling.html
new file mode 100644
index 0000000000..edf6793dfb
--- /dev/null
+++ b/dom/base/test/file_suppressed_events_and_scrolling.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+ <body><iframe srcdoc="
+ <html>
+ <head>
+ <script>
+ onload = function() {
+ // Ensure the layout is up-to-date and painted.
+ requestAnimationFrame(function() {
+ setTimeout(run);
+ })
+ }
+
+ function run() {
+ parent.opener.postMessage('doscroll', '*');
+ window.onscroll = function() {
+ parent.opener.postMessage('didscroll', '*');
+ }
+ let xhr = new XMLHttpRequest();
+ xhr.open('GET', 'slow.sjs', false);
+ xhr.send();
+ parent.opener.postMessage('xhr_done', '*');
+ }
+ </script>
+ </head>
+ <body style='height: 3000px; border: 1px solid black;'>
+ </body>
+ </html>
+ "></iframe></body>
+</html>
diff --git a/dom/base/test/file_suppressed_events_inner.html b/dom/base/test/file_suppressed_events_inner.html
new file mode 100644
index 0000000000..44cc45254d
--- /dev/null
+++ b/dom/base/test/file_suppressed_events_inner.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test event suppression</title>
+</head>
+<body>
+<div>Inner</div>
+<script type="application/javascript">
+
+window.onload = function() {
+ top.postMessage("ready", "*");
+};
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_suppressed_events_middle.html b/dom/base/test/file_suppressed_events_middle.html
new file mode 100644
index 0000000000..86b1f05374
--- /dev/null
+++ b/dom/base/test/file_suppressed_events_middle.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test event suppression</title>
+</head>
+<body>
+<div>Middle</div>
+<iframe src="http://mochi.test:8888/tests/dom/base/test/file_suppressed_events_inner.html"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_suppressed_events_top.html b/dom/base/test/file_suppressed_events_top.html
new file mode 100644
index 0000000000..ca031abb70
--- /dev/null
+++ b/dom/base/test/file_suppressed_events_top.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test event suppression</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" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div>Top</div>
+<script type="application/javascript">
+
+function waitForMessage(aMsg, aCallback) {
+ window.addEventListener("message", function handler(e) {
+ if (e.data != aMsg) {
+ return;
+ }
+
+ info(`received: ${e.data}`);
+ window.removeEventListener("message", handler);
+ if (aCallback) {
+ aCallback(e);
+ }
+ });
+}
+
+function waitForClickEvent(aElement, aWindow) {
+ return new Promise((aResolve) => {
+ aElement.addEventListener("click", aResolve, { once: true });
+ synthesizeMouseAtCenter(aElement, { type: "mousedown" }, aWindow);
+ synthesizeMouseAtCenter(aElement, { type: "mouseup" }, aWindow);
+ });
+}
+
+waitForMessage("ready", async function(e) {
+ await waitUntilApzStable();
+
+ let innerWin = e.source;
+ let innerDiv = innerWin.document.querySelector("div");
+
+ let eventCount = 0;
+ innerDiv.addEventListener("mousemove", function() {
+ eventCount++;
+ });
+
+ // Test that event handling is suppressed.
+ let utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.suppressEventHandling(true);
+ const TOTAL = 100;
+ for (let i = 0; i < TOTAL; i++) {
+ synthesizeMouseAtCenter(innerDiv, { type: "mousemove" }, innerWin);
+ }
+ utils.suppressEventHandling(false);
+
+ // Wait for click event to ensure we have received all mousemove events.
+ await waitForClickEvent(innerDiv, innerWin);
+ opener.info(`eventCount: ${eventCount}`);
+ opener.ok(eventCount < TOTAL, "event should be suspressed");
+
+ // Test that event handling is not suppressed.
+ eventCount = 0;
+ for (let i = 0; i < TOTAL; i++) {
+ synthesizeMouseAtCenter(innerDiv, { type: "mousemove" }, innerWin);
+ }
+
+ // Wait for click event to ensure we have received all mousemove events.
+ await waitForClickEvent(innerDiv, innerWin);
+ opener.info(`eventCount: ${eventCount}`);
+ opener.is(eventCount, TOTAL, "event should not be suspressed");
+
+ opener.postMessage("done", "*");
+});
+
+</script>
+<iframe src="http://example.org/tests/dom/base/test/file_suppressed_events_middle.html"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_suppressed_events_top_modalstate.html b/dom/base/test/file_suppressed_events_top_modalstate.html
new file mode 100644
index 0000000000..e20938bb28
--- /dev/null
+++ b/dom/base/test/file_suppressed_events_top_modalstate.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test event suppression</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" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div>Top</div>
+<script type="application/javascript">
+
+function waitForMessage(aMsg, aCallback) {
+ window.addEventListener("message", function handler(e) {
+ if (e.data != aMsg) {
+ return;
+ }
+
+ info(`received: ${e.data}`);
+ window.removeEventListener("message", handler);
+ if (aCallback) {
+ aCallback(e);
+ }
+ });
+}
+
+function waitForClickEvent(aElement, aWindow) {
+ return new Promise((aResolve) => {
+ aElement.addEventListener("click", aResolve, { once: true });
+ synthesizeMouseAtCenter(aElement, { type: "mousedown" }, aWindow);
+ synthesizeMouseAtCenter(aElement, { type: "mouseup" }, aWindow);
+ });
+}
+
+waitForMessage("ready", async function(e) {
+ await waitUntilApzStable();
+
+ let innerWin = e.source;
+ let innerDiv = innerWin.document.querySelector("div");
+
+ let eventCount = 0;
+ innerDiv.addEventListener("mousemove", function() {
+ eventCount++;
+ });
+
+ // Test that event handling is suppressed.
+ let utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.enterModalState();
+ const TOTAL = 100;
+ for (let i = 0; i < TOTAL; i++) {
+ synthesizeMouseAtCenter(innerDiv, { type: "mousemove" }, innerWin);
+ }
+ utils.leaveModalState();
+
+ // Wait for click event to ensure we have received all mousemove events.
+ await waitForClickEvent(innerDiv, innerWin);
+ opener.info(`eventCount: ${eventCount}`);
+ opener.ok(eventCount < TOTAL, "event should be suspressed");
+
+ // Test that event handling is not suppressed.
+ eventCount = 0;
+ for (let i = 0; i < TOTAL; i++) {
+ synthesizeMouseAtCenter(innerDiv, { type: "mousemove" }, innerWin);
+ }
+
+ // Wait for click event to ensure we have received all mousemove events.
+ await waitForClickEvent(innerDiv, innerWin);
+ opener.info(`eventCount: ${eventCount}`);
+ opener.is(eventCount, TOTAL, "event should not be suspressed");
+
+ opener.postMessage("done", "*");
+});
+
+</script>
+<iframe src="http://example.org/tests/dom/base/test/file_suppressed_events_middle.html"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_suppressed_events_top_xhr.html b/dom/base/test/file_suppressed_events_top_xhr.html
new file mode 100644
index 0000000000..79299e291e
--- /dev/null
+++ b/dom/base/test/file_suppressed_events_top_xhr.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test event suppression</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" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div>Top</div>
+<script type="application/javascript">
+
+function waitForMessage(aMsg, aCallback) {
+ window.addEventListener("message", function handler(e) {
+ if (e.data != aMsg) {
+ return;
+ }
+
+ info(`received: ${e.data}`);
+ window.removeEventListener("message", handler);
+ if (aCallback) {
+ aCallback(e);
+ }
+ });
+}
+
+function waitForClickEvent(aElement, aWindow) {
+ return new Promise((aResolve) => {
+ aElement.addEventListener("click", aResolve, { once: true });
+ synthesizeMouseAtCenter(aElement, { type: "mousedown" }, aWindow);
+ synthesizeMouseAtCenter(aElement, { type: "mouseup" }, aWindow);
+ });
+}
+
+waitForMessage("ready", async function(e) {
+ await waitUntilApzStable();
+
+ let innerWin = e.source;
+ let innerDiv = innerWin.document.querySelector("div");
+
+ let eventCount = 0;
+ innerDiv.addEventListener("mousemove", function() {
+ eventCount++;
+ });
+
+ // Test that event handling is suppressed.
+ let xhr = new XMLHttpRequest();
+ opener.info("xhr open");
+ xhr.open('GET', 'slow.sjs', false);
+
+ const TOTAL = 100;
+ for (let i = 0; i < TOTAL; i++) {
+ synthesizeMouseAtCenter(innerDiv, { type: "mousemove" }, innerWin);
+ }
+ xhr.send();
+ opener.info(`xhr done`);
+
+ // Wait for click event to ensure we have received all mousemove events.
+ await waitForClickEvent(innerDiv, innerWin);
+ opener.info(`eventCount: ${eventCount}`);
+ opener.ok(eventCount < TOTAL, "event should be suspressed");
+
+ // Test that event handling is not suppressed.
+ eventCount = 0;
+ for (let i = 0; i < TOTAL; i++) {
+ synthesizeMouseAtCenter(innerDiv, { type: "mousemove" }, innerWin);
+ }
+
+ // Wait for click event to ensure we have received all mousemove events.
+ await waitForClickEvent(innerDiv, innerWin);
+ opener.info(`eventCount: ${eventCount}`);
+ opener.is(eventCount, TOTAL, "event should not be suspressed");
+
+ opener.postMessage("done", "*");
+});
+
+</script>
+<iframe src="http://example.org/tests/dom/base/test/file_suppressed_events_middle.html"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_timer_flood.html b/dom/base/test/file_timer_flood.html
new file mode 100644
index 0000000000..dc729d7e42
--- /dev/null
+++ b/dom/base/test/file_timer_flood.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script>
+let count = 0;
+function cb() {
+ count += 1;
+ // Notify our parent that we are ready once the timer flood has
+ // warmed up.
+ if (count === 10000) {
+ window.parent.postMessage('STARTED', '*');
+ }
+ setTimeout(cb, 0);
+ setTimeout(cb, 0);
+}
+addEventListener('load', cb);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_title.xhtml b/dom/base/test/file_title.xhtml
new file mode 100644
index 0000000000..d1b04418aa
--- /dev/null
+++ b/dom/base/test/file_title.xhtml
@@ -0,0 +1 @@
+<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul' title='Test'/>
diff --git a/dom/base/test/file_toScreenRect.html b/dom/base/test/file_toScreenRect.html
new file mode 100644
index 0000000000..990d9326f2
--- /dev/null
+++ b/dom/base/test/file_toScreenRect.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
+<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
+<style>
+html,body {
+ margin: 0;
+ padding: 0;
+}
+#target {
+ position: absolute;
+ top: 150px;
+ left: 150px;
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+}
+</style>
+<div id="target"></div>
+<script>
+const isfuzzy = opener.isfuzzy.bind(opener);
+const add_task = opener.add_task.bind(opener);
+const original_finish = opener.SimpleTest.finish;
+const SimpleTest = opener.SimpleTest;
+SimpleTest.finish = function finish() {
+ self.close();
+ original_finish();
+};
+add_task(async () => {
+ await SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 1.5]]});
+ SpecialPowers.setFullZoom(window, 2.0);
+
+ const rect = target.getBoundingClientRect();
+ const screenPixelsPerCSSPixel = window.devicePixelRatio;
+
+ let rectOnScreen =
+ SpecialPowers.DOMWindowUtils.toScreenRect(rect.x, rect.y, rect.width, rect.height);
+ isfuzzy(rectOnScreen.x,
+ rect.x * screenPixelsPerCSSPixel +
+ window.mozInnerScreenX * screenPixelsPerCSSPixel, 0.01, "x");
+ isfuzzy(rectOnScreen.y,
+ rect.y * screenPixelsPerCSSPixel +
+ window.mozInnerScreenY * screenPixelsPerCSSPixel, 0.01, "y");
+
+ isfuzzy(rectOnScreen.width, rect.width * screenPixelsPerCSSPixel, 0.01, "width");
+ isfuzzy(rectOnScreen.height, rect.height * screenPixelsPerCSSPixel, 0.01, "height");
+});
+</script>
diff --git a/dom/base/test/file_use_counter_bfcache.html b/dom/base/test/file_use_counter_bfcache.html
new file mode 100644
index 0000000000..6baf738945
--- /dev/null
+++ b/dom/base/test/file_use_counter_bfcache.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script>
+let goneBack = false;
+let w;
+
+onload = function() {
+ w = window.open("file_use_counter_bfcache_helper.html?a", "_blank");
+};
+
+onmessage = function() {
+ switch (event.data) {
+ case "a-doc-loaded":
+ if (!goneBack) {
+ w.postMessage("click-b-link", "*");
+ }
+ break;
+ case "b-doc-loaded":
+ if (!goneBack) {
+ goneBack = true;
+ w.postMessage("go-back", "*");
+ }
+ break;
+ case "a-doc-shown":
+ if (goneBack) {
+ w.postMessage("set-use-counter", "*");
+ }
+ break;
+ case "did-set-use-counter":
+ w.postMessage("click-c-link", "*");
+ break;
+ case "c-doc-loaded":
+ w.close();
+ // Signal that we've finished.
+ location.hash = "#finished";
+ break;
+ }
+};
+</script>
diff --git a/dom/base/test/file_use_counter_bfcache_helper.html b/dom/base/test/file_use_counter_bfcache_helper.html
new file mode 100644
index 0000000000..a5da790ae6
--- /dev/null
+++ b/dom/base/test/file_use_counter_bfcache_helper.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<a href="file_use_counter_bfcache_helper.html?b">b</a>
+<a href="file_use_counter_bfcache_helper.html?c">c</a>
+<svg></svg>
+<script>
+let which = location.search.substring(1);
+
+if (which == "c") {
+ // Set the sentinel use counter.
+ let s = document.createElement("style");
+ s.textContent = "g { marker-mid: none; }";
+ document.body.append(s);
+}
+
+onload = function() {
+ window.opener.postMessage(`${which}-doc-loaded`, "*");
+};
+
+onmessage = function() {
+ switch (event.data) {
+ case "click-b-link":
+ document.querySelectorAll("a")[0].click();
+ break;
+ case "click-c-link":
+ document.querySelectorAll("a")[1].click();
+ break;
+ case "go-back":
+ history.back();
+ break;
+ case "set-use-counter":
+ document.querySelector("svg").getElementById("x");
+ window.opener.postMessage("did-set-use-counter", "*");
+ break;
+ }
+};
+
+onpageshow = function() {
+ window.opener.postMessage(`${which}-doc-shown`, "*");
+};
+</script>
diff --git a/dom/base/test/file_use_counter_outer.html b/dom/base/test/file_use_counter_outer.html
new file mode 100644
index 0000000000..1a7eb90f7c
--- /dev/null
+++ b/dom/base/test/file_use_counter_outer.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=968923
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 968923</title>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=968923">Mozilla Bug 968923</a>
+<img id="display" />
+<iframe id="content">
+
+</iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_use_counter_outer_display_none.html b/dom/base/test/file_use_counter_outer_display_none.html
new file mode 100644
index 0000000000..22c4c4c8ab
--- /dev/null
+++ b/dom/base/test/file_use_counter_outer_display_none.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=968923
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 968923</title>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=968923">Mozilla Bug 968923</a>
+<iframe id="content" style="display: none">
+
+</iframe>
+</body>
+</html>
diff --git a/dom/base/test/file_use_counter_style.html b/dom/base/test/file_use_counter_style.html
new file mode 100644
index 0000000000..52880c0e40
--- /dev/null
+++ b/dom/base/test/file_use_counter_style.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<style>
+ div {
+ background-image: none;
+ padding: 10px;
+ -moz-transform: scale(10);
+ /* Just a property we're unlikely to implement */
+ -webkit-padding-start: 58.5;
+ /* Sentinel use counter to signal that telemetry for this document has been captured */
+ marker-mid: initial;
+ }
+</style>
+<!-- We currently count even if we don't match it, but well just in case we change that... -->
+<div></div>
diff --git a/dom/base/test/file_use_counter_svg_currentScale.svg b/dom/base/test/file_use_counter_svg_currentScale.svg
new file mode 100644
index 0000000000..cf4d64aba0
--- /dev/null
+++ b/dom/base/test/file_use_counter_svg_currentScale.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="4in" height="3in" version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <desc>Test graphic for hitting currentScale
+ </desc>
+ <script type="text/javascript"> <![CDATA[
+ document.documentElement.currentScale = document.documentElement.currentScale;
+ ]]>
+ </script>
+ <image id="i1" x="200" y="200" width="100px" height="80px">
+ </image>
+ <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
+
+ <!-- Sentinel use counter to signal that telemetry for this document has been captured -->
+ <style>x { marker-mid: initial; }</style>
+</svg>
diff --git a/dom/base/test/file_use_counter_svg_fill_pattern.svg b/dom/base/test/file_use_counter_svg_fill_pattern.svg
new file mode 100644
index 0000000000..1cd84dd5e1
--- /dev/null
+++ b/dom/base/test/file_use_counter_svg_fill_pattern.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
+ xmlns="http://www.w3.org/2000/svg">
+ <desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
+ <!-- Outline the drawing area in blue -->
+ <rect fill="none" stroke="blue"
+ x="1" y="1" width="798" height="398"/>
+
+ <!-- The ellipse is filled using a triangle pattern paint server
+ and stroked with black -->
+ <ellipse fill="url(https://example.com/browser/dom/base/test/file_use_counter_svg_fill_pattern_definition.svg#TrianglePattern)" stroke="black" stroke-width="5"
+ cx="400" cy="200" rx="350" ry="150" />
+
+ <!-- Sentinel use counter to signal that telemetry for this document has been captured -->
+ <style>x { marker-mid: initial; }</style>
+</svg>
diff --git a/dom/base/test/file_use_counter_svg_fill_pattern_data.svg b/dom/base/test/file_use_counter_svg_fill_pattern_data.svg
new file mode 100644
index 0000000000..9a180b2432
--- /dev/null
+++ b/dom/base/test/file_use_counter_svg_fill_pattern_data.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
+ xmlns="http://www.w3.org/2000/svg">
+ <desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
+ <!-- Outline the drawing area in blue -->
+ <rect fill="none" stroke="blue"
+ x="1" y="1" width="798" height="398"/>
+
+ <!-- The ellipse is filled using a triangle pattern paint server
+ and stroked with black -->
+ <ellipse fill="url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iIAogICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI4Y20iIGhlaWdodD0iNGNtIiB2aWV3Qm94PSIwIDAgODAwIDQwMCIgdmVyc2lvbj0iMS4xIgogICAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGRlc2M+Qm9ycm93ZWQgZnJvbSBodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcvcHNlcnZlcnMuaHRtbDwvZGVzYz4KICA8ZGVmcz4KICAgIDxwYXR0ZXJuIGlkPSJUcmlhbmdsZVBhdHRlcm4iIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICAgICAgICB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIKICAgICAgICAgICAgIHZpZXdCb3g9IjAgMCAxMCAxMCIgPgogICAgICA8cGF0aCBkPSJNIDAgMCBMIDcgMCBMIDMuNSA3IHoiIGZpbGw9InJlZCIgZmlsbC1vcGFjaXR5PSIwLjciIHN0cm9rZT0iYmx1ZSIgLz4KICAgIDwvcGF0dGVybj4gCiAgPC9kZWZzPgo8L3N2Zz4K#TrianglePattern)" stroke="black" stroke-width="5"
+ cx="400" cy="200" rx="350" ry="150" />
+</svg>
diff --git a/dom/base/test/file_use_counter_svg_fill_pattern_definition.svg b/dom/base/test/file_use_counter_svg_fill_pattern_definition.svg
new file mode 100644
index 0000000000..a84292a63f
--- /dev/null
+++ b/dom/base/test/file_use_counter_svg_fill_pattern_definition.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
+ xmlns="http://www.w3.org/2000/svg">
+ <desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
+ <defs>
+ <pattern id="TrianglePattern" patternUnits="userSpaceOnUse"
+ x="0" y="0" width="100" height="100"
+ viewBox="0 0 10 10" >
+ <path d="M 0 0 L 7 0 L 3.5 7 z" fill="red" fill-opacity="0.7" stroke="blue" />
+ </pattern>
+ </defs>
+</svg>
diff --git a/dom/base/test/file_use_counter_svg_fill_pattern_internal.svg b/dom/base/test/file_use_counter_svg_fill_pattern_internal.svg
new file mode 100644
index 0000000000..47adafe38c
--- /dev/null
+++ b/dom/base/test/file_use_counter_svg_fill_pattern_internal.svg
@@ -0,0 +1,24 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
+ xmlns="http://www.w3.org/2000/svg">
+ <desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
+ <!-- Outline the drawing area in blue -->
+ <rect fill="none" stroke="blue"
+ x="1" y="1" width="798" height="398"/>
+
+ <defs>
+ <pattern id="TrianglePattern" patternUnits="userSpaceOnUse"
+ x="0" y="0" width="100" height="100"
+ viewBox="0 0 10 10" >
+ <path d="M 0 0 L 7 0 L 3.5 7 z" fill="red" fill-opacity="0.7" stroke="blue" />
+ </pattern>
+ </defs>
+
+ <!-- The ellipse is filled using a triangle pattern paint server
+ and stroked with black -->
+ <ellipse fill="url(#TrianglePattern)" stroke="black" stroke-width="5"
+ cx="400" cy="200" rx="350" ry="150" />
+
+ <!-- Sentinel use counter to signal that telemetry for this document has been captured -->
+ <style>x { marker-mid: initial; }</style>
+</svg>
diff --git a/dom/base/test/file_use_counter_svg_getElementById.svg b/dom/base/test/file_use_counter_svg_getElementById.svg
new file mode 100644
index 0000000000..7cd12ba315
--- /dev/null
+++ b/dom/base/test/file_use_counter_svg_getElementById.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="4in" height="3in" version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <desc>Test graphic for hitting getElementById
+ </desc>
+ <image id="i1" x="200" y="200" width="100px" height="80px">
+ </image>
+ <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
+ <script type="text/javascript"> <![CDATA[
+ var image = document.documentElement.getElementById("i1");
+ image.addEventListener("load",
+ function() {
+ document.documentElement.removeAttribute("class");
+ },
+ false);
+ ]]>
+ </script>
+
+ <!-- Sentinel use counter to signal that telemetry for this document has been captured -->
+ <style>x { marker-mid: initial; }</style>
+</svg>
diff --git a/dom/base/test/file_viewport_metrics_on_landscape_content.html b/dom/base/test/file_viewport_metrics_on_landscape_content.html
new file mode 100644
index 0000000000..02b079aeac
--- /dev/null
+++ b/dom/base/test/file_viewport_metrics_on_landscape_content.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, minimum-scale=0.5">
+<style>
+html {
+ scrollbar-width: none; /* avoid scrollbar width is included in some metrics */
+}
+html, body {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ overflow: none;
+}
+#twice-width {
+ width: 200%;
+ height: 100%;
+ position: absolute;
+}
+</style>
+<div id="twice-width"></div>
+<script>
+
+const is = opener.is.bind(opener);
+const todo_is = opener.todo_is.bind(opener);
+const add_task = opener.add_task.bind(opener);
+const original_finish = opener.SimpleTest.finish;
+const SimpleTest = opener.SimpleTest;
+
+SimpleTest.finish = function finish() {
+ self.close();
+ original_finish();
+}
+
+add_task(async () => {
+ // Explicitly set to 0.5x so that this test doesn't need to reply on our
+ // auto initial-scale calculation.
+ SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(0.5);
+ is(window.visualViewport.scale, 0.5, "The content should be scaled by 0.5x");
+
+ // Now the visual viewport size is same as the layout viewport.
+ const layoutViewportHeight = window.visualViewport.height;
+
+ todo_is(window.innerHeight, layoutViewportHeight,
+ "window.innerHeight should reflect the layout viewport (Bug 1598487)");
+ is(document.documentElement.scrollHeight, layoutViewportHeight,
+ "The root element's scrollHeight should be the layout viewport height");
+ is(document.documentElement.getBoundingClientRect().height,
+ layoutViewportHeight / 2,
+ "The content height should be half of the layout viewport height");
+
+ // Set scale to 1.0x so that the visual viport size becomes 0.5x of the layout
+ // viewport.
+ SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(1);
+ is(window.visualViewport.scale, 1, "The content should be scaled by 1.0x");
+ is(window.visualViewport.height, layoutViewportHeight / 2,
+ "Now the visual viewport height should be changed to half of the layout " +
+ "viewport height");
+ todo_is(window.innerHeight, layoutViewportHeight,
+ "window.innerHeight shouldn't be changed (Bug 1598487)");
+ is(document.documentElement.scrollHeight, layoutViewportHeight,
+ "The root element's scrollHeight shouldn't be changed");
+});
+</script>
+</html>
diff --git a/dom/base/test/file_viewport_scroll_quirks.html b/dom/base/test/file_viewport_scroll_quirks.html
new file mode 100644
index 0000000000..992b8a9968
--- /dev/null
+++ b/dom/base/test/file_viewport_scroll_quirks.html
@@ -0,0 +1 @@
+<html><body style='height:2000px; width:2000px;'>
diff --git a/dom/base/test/file_viewport_scroll_xml.xml b/dom/base/test/file_viewport_scroll_xml.xml
new file mode 100644
index 0000000000..1453e9b1ea
--- /dev/null
+++ b/dom/base/test/file_viewport_scroll_xml.xml
@@ -0,0 +1 @@
+<?xml-stylesheet href='data:text/css,html { display:block; height:2000px; width:2000px; }'?><foo><html></html></foo>
diff --git a/dom/base/test/file_webaudio_startstop.html b/dom/base/test/file_webaudio_startstop.html
new file mode 100644
index 0000000000..c0e4fafb01
--- /dev/null
+++ b/dom/base/test/file_webaudio_startstop.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<script>
+var ac = new AudioContext();
+var runningPromise = new Promise(resolve => {
+ ac.onstatechange = event => {
+ if (ac.state == "running") {
+ resolve();
+ }
+ };
+});
+
+var osc = ac.createOscillator();
+osc.connect(ac.destination);
+osc.start(0);
+osc.stop(osc.context.currentTime + 2.0);
+
+var suspendPromise;
+function suspendAC() {
+ runningPromise.then(() => {
+ suspendPromise = ac.suspend();
+ });
+}
+
+var resumePromise;
+function resumeAC() {
+ suspendPromise.then(() => {
+ resumePromise = ac.resume();
+ });
+}
+
+function closeAC() {
+ resumePromise.then(() => {
+ ac.close();
+ });
+}
+</script>
diff --git a/dom/base/test/file_window_close.html b/dom/base/test/file_window_close.html
new file mode 100644
index 0000000000..5adec04ec4
--- /dev/null
+++ b/dom/base/test/file_window_close.html
@@ -0,0 +1,68 @@
+<html>
+ <head>
+ <script>
+ var b = new BroadcastChannel("windowclose");
+
+ function isInitialLoad() {
+ return location.search.substr(1) != "withhistory" || history.length == 1;
+ }
+
+ function run() {
+ if (location.search.substr(1) == "withhistory") {
+ // An entry for the initial load, pushState, iframe and the next page.
+ if (history.length == 4) {
+ // We're coming back from history.
+ function listener(m) {
+ if (m.message.includes("Scripts may not close windows that were not opened by script.")) {
+ SpecialPowers.postConsoleSentinel();
+ SpecialPowers.pushPrefEnv({ set: [["dom.allow_scripts_to_close_windows", true]]}).then(
+ function() {
+ window.onunload = function() {
+ b.postMessage('blocked');
+ b.close();
+ };
+ window.close();
+ });
+ }
+ }
+ SpecialPowers.registerConsoleListener(listener);
+ window.onunload = function() {
+ SpecialPowers.postConsoleSentinel();
+ b.postMessage('closed');
+ b.close();
+ };
+ window.close();
+ } else {
+ // Load a page which will call history.back()
+ location.href = "file_window_close_2.html";
+ }
+ } else {
+ onunload = function() {
+ b.postMessage('closed');
+ b.close();
+ };
+ window.close();
+ }
+ }
+
+ function init() {
+ if (isInitialLoad()) {
+ // Add some data to the session history.
+ history.pushState("foo", "foo");
+ var ifr = document.getElementsByTagName("iframe")[0];
+ ifr.onload = run;
+ ifr.src = "data:text/html,random data";
+ } else {
+ run();
+ }
+ }
+ window.onpageshow = () => {
+ setTimeout(init);
+ }
+
+ </script>
+ </head>
+ <body>
+ <iframe></iframe>
+ </body>
+</html>
diff --git a/dom/base/test/file_window_close_2.html b/dom/base/test/file_window_close_2.html
new file mode 100644
index 0000000000..c06ec90a8b
--- /dev/null
+++ b/dom/base/test/file_window_close_2.html
@@ -0,0 +1,4 @@
+<html>
+ <body onload="setTimeout('history.back();');">
+ </body>
+</html>
diff --git a/dom/base/test/file_window_focus_by_close_and_open.html b/dom/base/test/file_window_focus_by_close_and_open.html
new file mode 100644
index 0000000000..ab5ad72ae3
--- /dev/null
+++ b/dom/base/test/file_window_focus_by_close_and_open.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+<script>
+SimpleTest.waitForFocus(() => {
+ finished();
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/file_x-frame-options_main.html b/dom/base/test/file_x-frame-options_main.html
new file mode 100644
index 0000000000..903f951e08
--- /dev/null
+++ b/dom/base/test/file_x-frame-options_main.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+<title>X-Frame-Options tests</title>
+<script type="text/javascript">
+// This frame loading means all subframes have either loaded or errored out. We
+// can now tell the test harness to check each subframe for the expected result.
+window.addEventListener('load', parent.testFramesLoaded);
+</script>
+</head>
+<body>
+
+<iframe id="control1" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=control1"></iframe><br>
+<iframe id="control2" src="http://example.com/tests/dom/base/test/file_x-frame-options_page.sjs?testid=control2"></iframe><br>
+<iframe id="deny" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny"></iframe><br>
+<iframe id="sameorigin1" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin1&xfo=sameorigin"></iframe><br>
+<iframe id="sameorigin2" src="http://example.com/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin2&xfo=sameorigin"></iframe><br>
+<iframe id="sameorigin5" src="http://example.com/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin5&xfo=sameorigin2"></iframe><br>
+<iframe id="sameorigin6" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin6&xfo=sameorigin2"></iframe><br>
+<iframe id="sameorigin7" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin7&xfo=sameorigin3"></iframe><br>
+<iframe id="sameorigin8" src="http://example.com/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin8&xfo=sameorigin3"></iframe><br>
+<iframe id="mixedpolicy" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=mixedpolicy&xfo=mixedpolicy"></iframe><br>
+<iframe id="allow-from-allow" src="http://example.com/tests/dom/base/test/file_x-frame-options_page.sjs?testid=allow-from-allow&xfo=afa"></iframe><br>
+<iframe id="allow-from-deny" src="http://example.com/tests/dom/base/test/file_x-frame-options_page.sjs?testid=allow-from-deny&xfo=afd"></iframe><br>
+<iframe id="sameorigin-multipart" src="http://example.com/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin-multipart&xfo=sameorigin&multipart=1"></iframe><br>
+<iframe id="sameorigin-multipart2" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin-multipart2&xfo=sameorigin&multipart=1"></iframe><br>
+
+<!-- added for bug 836132 -->
+<script type="text/javascript">
+
+ function addFrame(test, xfo) {
+ var baseurl = "http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs";
+ var ifr = "<iframe id='" + test + "'" + "src='" + baseurl + "?testid=" + test + "&xfo=" + xfo + "' style='border:2px solid red;'></iframe>";
+ document.write(ifr);
+ }
+
+ addFrame("allow-from-allow-1", "afa1");
+ for (var i = 1; i<=14; i++)
+ addFrame("allow-from-deny-"+i, "afd"+i);
+
+</script>
+
+
+</body>
+</html>
diff --git a/dom/base/test/file_x-frame-options_page.sjs b/dom/base/test/file_x-frame-options_page.sjs
new file mode 100644
index 0000000000..13c9aa7cac
--- /dev/null
+++ b/dom/base/test/file_x-frame-options_page.sjs
@@ -0,0 +1,67 @@
+// SJS file for X-Frame-Options mochitests
+function handleRequest(request, response) {
+ var query = {};
+ var BOUNDARY = "BOUNDARYOMG3984";
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ if (query.multipart == "1") {
+ response.setHeader(
+ "Content-Type",
+ "multipart/x-mixed-replace;boundary=" + BOUNDARY,
+ false
+ );
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.write("--" + BOUNDARY + "\r\n");
+ response.write("Content-Type: text/html\r\n\r\n");
+ } else {
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Cache-Control", "no-cache", false);
+ }
+
+ var testHeaders = {
+ deny: "DENY",
+ sameorigin: "SAMEORIGIN",
+ sameorigin2: "SAMEORIGIN, SAMEORIGIN",
+ sameorigin3: "SAMEORIGIN,SAMEORIGIN , SAMEORIGIN",
+ mixedpolicy: "DENY,SAMEORIGIN",
+
+ /* added for bug 836132 */
+ afa: "ALLOW-FROM http://mochi.test:8888/",
+ afd: "ALLOW-FROM http://example.com/",
+ afa1: "ALLOW-FROM http://mochi.test:8888",
+ afd1: "ALLOW-FROM:example.com",
+ afd2: "ALLOW-FROM: example.com",
+ afd3: "ALLOW-FROM example.com",
+ afd4: "ALLOW-FROM:http://example.com",
+ afd5: "ALLOW-FROM: http://example.com",
+ afd6: "ALLOW-FROM http://example.com",
+ afd7: "ALLOW-FROM:mochi.test:8888",
+ afd8: "ALLOW-FROM: mochi.test:8888",
+ afd9: "ALLOW-FROM:http://mochi.test:8888",
+ afd10: "ALLOW-FROM: http://mochi.test:8888",
+ afd11: "ALLOW-FROM mochi.test:8888",
+ afd12: "ALLOW-FROM",
+ afd13: "ALLOW-FROM ",
+ afd14: "ALLOW-FROM:",
+ };
+
+ if (testHeaders.hasOwnProperty(query.xfo)) {
+ response.setHeader("X-Frame-Options", testHeaders[query.xfo], false);
+ }
+
+ // from the test harness we'll be checking for the presence of this element
+ // to test if the page loaded
+ response.write('<h1 id="test">' + query.testid + "</h1>");
+
+ if (query.testid == "postmessage") {
+ response.write("<script>parent.opener.postMessage('ok', '*');</script>");
+ }
+
+ if (query.multipart == "1") {
+ response.write("\r\n--" + BOUNDARY + "\r\n");
+ }
+}
diff --git a/dom/base/test/file_xhtmlserializer_1.xhtml b/dom/base/test/file_xhtmlserializer_1.xhtml
new file mode 100644
index 0000000000..64271ce2ce
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1.xhtml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong> adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/file_xhtmlserializer_1_bodyonly.xhtml b/dom/base/test/file_xhtmlserializer_1_bodyonly.xhtml
new file mode 100644
index 0000000000..fbefe91d6e
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_bodyonly.xhtml
@@ -0,0 +1,56 @@
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_format.xhtml b/dom/base/test/file_xhtmlserializer_1_format.xhtml
new file mode 100644
index 0000000000..d62cc367ba
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_format.xhtml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+ </head>
+ <body>
+ <p>Hello world</p>
+ <p> Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+ adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis
+ ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent
+ taciti <span>sociosqu ad litora</span> torquent <a
+ href="file_htmlserializer_1_result1.html">per conubia</a>
+ nostra, per inceptos hymenaeos. </p>
+ <ul>
+ <li>Nam tellus massa,éàèçù</li>
+ <li> fringilla aliquam,</li>
+ <li> fermentum sit amet,</li>
+ <li>posuere ac,</li>
+ <li> est.</li>
+ </ul>
+ <div> Duis tristique egestas ligula. Mauris quis felis. </div>
+ <script id="script" type="text/javascript"></script>
+ <script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+ <ol>
+ <li>Fusce a ipsum</li>
+ <li> non lacus posuere aliquet.</li>
+ <li> Sed fermentum posuere nulla</li>
+ <li> Donec tempor.</li>
+ </ol>
+ Donec sollicitudin tortor
+ <!-- test on
+comments -->
+ <pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ ut gravida eros <br />
+ leo ut libero
+ <!-- empty element: end tag should be generated for backward compatibility with HTML -->
+ <p></p>
+ <noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+ <p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus
+ aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+ <pre xmlns="http://mozilla.org/ns/foo">lacinia
+ <em>libero</em> ullamcorper laoreet.<br/> Cras quis<br/> nisi at
+ odio<br/> consectetuer molestie. Curabitur consectetuer urna a
+ sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in
+ faucibus orci luctus et ultrices posuere cubilia Curae; Sed
+ sollicitudin, nulla at pharetra rutrum,
+ <br/>
+ lacus risus pulvinar ante.
+ </pre>
+ </body>
+</html>
diff --git a/dom/base/test/file_xhtmlserializer_1_linebreak.xhtml b/dom/base/test/file_xhtmlserializer_1_linebreak.xhtml
new file mode 100644
index 0000000000..a0aecdd2c6
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_linebreak.xhtml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_links.xhtml b/dom/base/test/file_xhtmlserializer_1_links.xhtml
new file mode 100644
index 0000000000..0c2814311b
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_links.xhtml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="http://mochi.test:8888/tests/dom/base/test/file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/file_xhtmlserializer_1_nested_body.xhtml b/dom/base/test/file_xhtmlserializer_1_nested_body.xhtml
new file mode 100644
index 0000000000..120f8e7dcb
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_nested_body.xhtml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+<body><p>this is an other body element</p></body></body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_no_body.xhtml b/dom/base/test/file_xhtmlserializer_1_no_body.xhtml
new file mode 100644
index 0000000000..6f5055bd57
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_no_body.xhtml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_noflag.xhtml b/dom/base/test/file_xhtmlserializer_1_noflag.xhtml
new file mode 100644
index 0000000000..a0aecdd2c6
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_noflag.xhtml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_noformatpre.xhtml b/dom/base/test/file_xhtmlserializer_1_noformatpre.xhtml
new file mode 100644
index 0000000000..a5eb6e9692
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_noformatpre.xhtml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.
+
+ Cras quis
+
+ nisi at odio
+
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum,
+
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_raw.xhtml b/dom/base/test/file_xhtmlserializer_1_raw.xhtml
new file mode 100644
index 0000000000..d13fce2ccd
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_raw.xhtml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong> adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_sibling_body.xhtml b/dom/base/test/file_xhtmlserializer_1_sibling_body.xhtml
new file mode 100644
index 0000000000..9ef4840e36
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_sibling_body.xhtml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body><p>this is an other body element</p></body><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_sibling_body_only_body.xhtml b/dom/base/test/file_xhtmlserializer_1_sibling_body_only_body.xhtml
new file mode 100644
index 0000000000..f9f92a0670
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_sibling_body_only_body.xhtml
@@ -0,0 +1,56 @@
+<body><p>this is an other body element</p></body><body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em> ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_1_wrap.xhtml b/dom/base/test/file_xhtmlserializer_1_wrap.xhtml
new file mode 100644
index 0000000000..6b156278ad
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_1_wrap.xhtml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>Test for html serializer</title>
+
+</head>
+<body>
+<p>Hello world</p> <p>
+
+ Lorem ipsum dolor sit amet, <strong>consectetuer</strong>
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti <span>sociosqu
+ ad
+ litora</span> torquent <a href="file_htmlserializer_1_result1.html">per
+ conubia</a>
+nostra, per inceptos hymenaeos. </p>
+
+
+<ul><li>Nam tellus massa,éàèçù</li><li>
+ fringilla
+aliquam,</li><li> fermentum sit amet,</li><li>posuere ac,</li><li> est.</li></ul>
+<div> Duis tristique egestas ligula. Mauris quis felis. </div>
+<script id="script" type="text/javascript"></script>
+<script type="text/javascript">
+//<![CDATA[
+// a script which does nothing
+
+function nothing() {
+ var hey="hello";
+ var aLongLine="consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere";
+}
+var a=3, b=4, c=7;
+// here we test the non-serialization of xml character into javascript content
+var d = a < b && a > c;
+//]]>
+</script>
+
+<ol><li>Fusce
+ a ipsum</li><li> non lacus posuere aliquet.</li><li> Sed fermentum
+posuere nulla</li><li> Donec tempor.</li></ol>
+Donec sollicitudin tortor
+<!-- test on
+comments -->
+<pre>lacinia <em>libero</em> ullamcorper laoreet.<br />
+ Cras quis<br />
+ nisi at odio<br />
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at pharetra rutrum, <br />
+lacus risus pulvinar ante.
+</pre>
+ut gravida eros <br />leo ut libero
+<!-- empty element: end tag should be generated for backward compatibility with HTML -->
+<p></p>
+<noscript>
+<p>Curabitur consectetuer urna a sem. Nunc non urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci luctus</p></noscript>
+<p>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus
+aliquet lectus. Nunc vitae eros. Class aptent taciti</p>
+<pre xmlns="http://mozilla.org/ns/foo">lacinia <em>libero</em>
+ullamcorper laoreet.<br/>
+ Cras quis<br/>
+ nisi at odio<br/>
+ consectetuer molestie. Curabitur consectetuer urna a sem. Nunc non
+urna. Cras in massa. Vestibulum ante ipsum primis in faucibus orci
+luctus et ultrices posuere cubilia Curae; Sed sollicitudin, nulla at
+pharetra rutrum, <br/>
+lacus risus pulvinar ante.
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_2.xhtml b/dom/base/test/file_xhtmlserializer_2.xhtml
new file mode 100644
index 0000000000..2a9c55b95d
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_2.xhtml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Test for html serializer with entities</title>
+</head>
+<body>
+
+<p>The basic set is just "&nbsp;" &amp; &lt; &gt; &quot; for interoperability with older products that don't support &alpha; and friends.</p>
+
+<p>latin1 &iexcl; &cent; &pound; &curren; &yen; &brvbar; &sect; &uml; &copy; &ordf; &laquo; &not; &shy; &reg; &macr; &deg; &plusmn; &sup2; &sup3; &acute;
+&micro; &para; &middot; &cedil; &sup1; &ordm; &raquo; &frac14; &frac12; &frac34; &iquest; &Agrave; &Aacute; &Acirc; &Atilde; &Auml; &Aring; &AElig;
+&Ccedil; &Egrave; &Eacute; &Ecirc; &Euml; &Igrave; &Iacute; &Icirc; &Iuml; &ETH; &Ntilde; &Ograve; &Oacute; &Ocirc; &Otilde; &Ouml; &times; &Oslash;
+&Ugrave; &Uacute; &Ucirc; &Uuml; &Yacute; &THORN; &szlig; &agrave; &aacute; &acirc; &atilde; &auml; &aring; &aelig; &ccedil; &egrave; &eacute; &ecirc;
+&euml; &igrave; &iacute; &icirc; &iuml; &eth; &ntilde; &ograve; &oacute; &ocirc; &otilde; &ouml; &divide; &oslash; &ugrave; &uacute; &ucirc; &uuml; &yacute;
+&thorn; &yuml; </p>
+<p>symbols, math.. &fnof; &Alpha; &Beta; &Gamma; &Delta; &Epsilon; &Zeta; &Eta; &Theta; &Iota; &Kappa; &Lambda; &Mu; &Nu; &Xi; &Omicron; &Pi; &Rho; &Sigma; &Tau; &Upsilon;
+&Phi; &Chi; &Psi; &Omega; &alpha; &beta; &gamma; &delta; &epsilon; &zeta; &eta; &theta; &iota; &kappa; &lambda; &mu; &nu; &xi; &omicron; &pi; &rho; &sigmaf;
+&sigma; &tau; &upsilon; &phi; &chi; &psi; &omega; &thetasym; &upsih; &piv; &bull; &hellip; &prime; &Prime; &oline; &frasl; &weierp; &image; &real;
+&trade; &alefsym; &larr; &uarr; &rarr; &darr; &harr; &crarr; &lArr; &uArr; &rArr; &dArr; &hArr; &forall; &part; &exist; &empty; &nabla; &isin; &notin;
+&ni; &prod; &sum; &minus; &lowast; &radic; &prop; &infin; &ang; &and; &or; &cap; &cup; &int; &there4; &sim; &cong; &asymp; &ne; &equiv; &le; &ge;
+&sub; &sup; &nsub; &sube; &supe; &oplus; &otimes; &perp; &sdot; &lceil; &rceil; &lfloor; &rfloor; &lang; &rang; &loz; &spades; &clubs; &hearts; &diams;
+</p>
+<p> others
+&OElig; &oelig; &Scaron; &scaron; &Yuml; &circ; &tilde; &ensp; &emsp; &thinsp; &zwnj; &zwj; &lrm; &rlm;&ndash;&mdash; &lsquo; &rsquo;
+&sbquo;&ldquo; &rdquo; &bdquo; &dagger; &Dagger; &permil; &lsaquo; &rsaquo; &euro;
+</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_2_basic.xhtml b/dom/base/test/file_xhtmlserializer_2_basic.xhtml
new file mode 100644
index 0000000000..c35cc48cf8
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_2_basic.xhtml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=" />
+ <title>Test for html serializer with entities</title>
+</head>
+<body>
+
+<p>The basic set is just " " &amp; &lt; &gt; " for interoperability with older products that don't support α and friends.</p>
+
+<p>latin1 ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´
+µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À à Â Ã Ä Å Æ
+Ç È É Ê Ë Ì à Î à à Ñ Ò Ó Ô Õ Ö × Ø
+Ù Ú Û Ü à Þ ß à á â ã ä å æ ç è é ê
+ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý
+þ ÿ </p>
+<p>symbols, math.. ƒ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ ΠΞ Ο Π Ρ Σ Τ Υ
+Φ Χ Ψ Ω α β γ δ ε ζ η θ ι κ λ μ ν ξ ο Ï€ Ï Ï‚
+σ τ υ φ χ ψ ω ϑ ϒ ϖ • … ′ ″ ‾ ℠℘ ℑ ℜ
+™ ℵ ↠↑ → ↓ ↔ ↵ ⇠⇑ ⇒ ⇓ ⇔ ∀ ∂ ∃ ∅ ∇ ∈ ∉
+∋ ∠∑ − ∗ √ ∠∞ ∠ ∧ ∨ ∩ ∪ ∫ ∴ ∼ ≅ ≈ ≠ ≡ ≤ ≥
+⊂ ⊃ ⊄ ⊆ ⊇ ⊕ ⊗ ⊥ ⋅ ⌈ ⌉ ⌊ ⌋ ⟨ ⟩ ◊ ♠ ♣ ♥ ♦
+</p>
+<p> others
+Å’ Å“ Å  Å¡ Ÿ ˆ Ëœ       ‌ †‎ â€â€“— ‘ ’
+‚“ †„ † ‡ ‰ ‹ › €
+</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_2_enthtml.xhtml b/dom/base/test/file_xhtmlserializer_2_enthtml.xhtml
new file mode 100644
index 0000000000..0ba1c8421c
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_2_enthtml.xhtml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=" />
+ <title>Test for html serializer with entities</title>
+</head>
+<body>
+
+<p>The basic set is just &nbsp; &amp; &lt; &gt; " for interoperability with older products that don't support &alpha; and friends.</p>
+
+<p>latin1 &iexcl; &cent; &pound; &curren; &yen; &brvbar; &sect; &uml;
+&copy; &ordf; &laquo; &not; &shy; &reg; &macr; &deg; &plusmn; &sup2;
+&sup3; &acute;
+&micro; &para; &middot; &cedil; &sup1; &ordm; &raquo; &frac14; &frac12;
+&frac34; &iquest; &Agrave; &Aacute; &Acirc; &Atilde; &Auml; &Aring;
+&AElig;
+&Ccedil; &Egrave; &Eacute; &Ecirc; &Euml; &Igrave; &Iacute; &Icirc;
+&Iuml; &ETH; &Ntilde; &Ograve; &Oacute; &Ocirc; &Otilde; &Ouml; &times;
+&Oslash;
+&Ugrave; &Uacute; &Ucirc; &Uuml; &Yacute; &THORN; &szlig; &agrave;
+&aacute; &acirc; &atilde; &auml; &aring; &aelig; &ccedil; &egrave;
+&eacute; &ecirc;
+&euml; &igrave; &iacute; &icirc; &iuml; &eth; &ntilde; &ograve; &oacute;
+ &ocirc; &otilde; &ouml; &divide; &oslash; &ugrave; &uacute; &ucirc;
+&uuml; &yacute;
+&thorn; &yuml; </p>
+<p>symbols, math.. &fnof; &Alpha; &Beta; &Gamma; &Delta; &Epsilon;
+&Zeta; &Eta; &Theta; &Iota; &Kappa; &Lambda; &Mu; &Nu; &Xi; &Omicron;
+&Pi; &Rho; &Sigma; &Tau; &Upsilon;
+&Phi; &Chi; &Psi; &Omega; &alpha; &beta; &gamma; &delta; &epsilon;
+&zeta; &eta; &theta; &iota; &kappa; &lambda; &mu; &nu; &xi; &omicron;
+&pi; &rho; &sigmaf;
+&sigma; &tau; &upsilon; &phi; &chi; &psi; &omega; &thetasym; &upsih;
+&piv; &bull; &hellip; &prime; &Prime; &oline; &frasl; &weierp; &image;
+&real;
+&trade; &alefsym; &larr; &uarr; &rarr; &darr; &harr; &crarr; &lArr;
+&uArr; &rArr; &dArr; &hArr; &forall; &part; &exist; &empty; &nabla;
+&isin; &notin;
+&ni; &prod; &sum; &minus; &lowast; &radic; &prop; &infin; &ang; &and;
+&or; &cap; &cup; &int; &there4; &sim; &cong; &asymp; &ne; &equiv; &le;
+&ge;
+&sub; &sup; &nsub; &sube; &supe; &oplus; &otimes; &perp; &sdot; &lceil;
+&rceil; &lfloor; &rfloor; &lang; &rang; &loz; &spades; &clubs; &hearts;
+&diams;
+</p>
+<p> others
+&OElig; &oelig; &Scaron; &scaron; &Yuml; &circ; &tilde; &ensp; &emsp;
+&thinsp; &zwnj; &zwj; &lrm; &rlm;&ndash;&mdash; &lsquo; &rsquo;
+&sbquo;&ldquo; &rdquo; &bdquo; &dagger; &Dagger; &permil; &lsaquo;
+&rsaquo; &euro;
+</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_2_entw3c.xhtml b/dom/base/test/file_xhtmlserializer_2_entw3c.xhtml
new file mode 100644
index 0000000000..0ba1c8421c
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_2_entw3c.xhtml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=" />
+ <title>Test for html serializer with entities</title>
+</head>
+<body>
+
+<p>The basic set is just &nbsp; &amp; &lt; &gt; " for interoperability with older products that don't support &alpha; and friends.</p>
+
+<p>latin1 &iexcl; &cent; &pound; &curren; &yen; &brvbar; &sect; &uml;
+&copy; &ordf; &laquo; &not; &shy; &reg; &macr; &deg; &plusmn; &sup2;
+&sup3; &acute;
+&micro; &para; &middot; &cedil; &sup1; &ordm; &raquo; &frac14; &frac12;
+&frac34; &iquest; &Agrave; &Aacute; &Acirc; &Atilde; &Auml; &Aring;
+&AElig;
+&Ccedil; &Egrave; &Eacute; &Ecirc; &Euml; &Igrave; &Iacute; &Icirc;
+&Iuml; &ETH; &Ntilde; &Ograve; &Oacute; &Ocirc; &Otilde; &Ouml; &times;
+&Oslash;
+&Ugrave; &Uacute; &Ucirc; &Uuml; &Yacute; &THORN; &szlig; &agrave;
+&aacute; &acirc; &atilde; &auml; &aring; &aelig; &ccedil; &egrave;
+&eacute; &ecirc;
+&euml; &igrave; &iacute; &icirc; &iuml; &eth; &ntilde; &ograve; &oacute;
+ &ocirc; &otilde; &ouml; &divide; &oslash; &ugrave; &uacute; &ucirc;
+&uuml; &yacute;
+&thorn; &yuml; </p>
+<p>symbols, math.. &fnof; &Alpha; &Beta; &Gamma; &Delta; &Epsilon;
+&Zeta; &Eta; &Theta; &Iota; &Kappa; &Lambda; &Mu; &Nu; &Xi; &Omicron;
+&Pi; &Rho; &Sigma; &Tau; &Upsilon;
+&Phi; &Chi; &Psi; &Omega; &alpha; &beta; &gamma; &delta; &epsilon;
+&zeta; &eta; &theta; &iota; &kappa; &lambda; &mu; &nu; &xi; &omicron;
+&pi; &rho; &sigmaf;
+&sigma; &tau; &upsilon; &phi; &chi; &psi; &omega; &thetasym; &upsih;
+&piv; &bull; &hellip; &prime; &Prime; &oline; &frasl; &weierp; &image;
+&real;
+&trade; &alefsym; &larr; &uarr; &rarr; &darr; &harr; &crarr; &lArr;
+&uArr; &rArr; &dArr; &hArr; &forall; &part; &exist; &empty; &nabla;
+&isin; &notin;
+&ni; &prod; &sum; &minus; &lowast; &radic; &prop; &infin; &ang; &and;
+&or; &cap; &cup; &int; &there4; &sim; &cong; &asymp; &ne; &equiv; &le;
+&ge;
+&sub; &sup; &nsub; &sube; &supe; &oplus; &otimes; &perp; &sdot; &lceil;
+&rceil; &lfloor; &rfloor; &lang; &rang; &loz; &spades; &clubs; &hearts;
+&diams;
+</p>
+<p> others
+&OElig; &oelig; &Scaron; &scaron; &Yuml; &circ; &tilde; &ensp; &emsp;
+&thinsp; &zwnj; &zwj; &lrm; &rlm;&ndash;&mdash; &lsquo; &rsquo;
+&sbquo;&ldquo; &rdquo; &bdquo; &dagger; &Dagger; &permil; &lsaquo;
+&rsaquo; &euro;
+</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_xhtmlserializer_2_latin1.xhtml b/dom/base/test/file_xhtmlserializer_2_latin1.xhtml
new file mode 100644
index 0000000000..59b564ca77
--- /dev/null
+++ b/dom/base/test/file_xhtmlserializer_2_latin1.xhtml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=" />
+ <title>Test for html serializer with entities</title>
+</head>
+<body>
+
+<p>The basic set is just &nbsp; &amp; &lt; &gt; " for interoperability with older products that don't support α and friends.</p>
+
+<p>latin1 &iexcl; &cent; &pound; &curren; &yen; &brvbar; &sect; &uml;
+&copy; &ordf; &laquo; &not; &shy; &reg; &macr; &deg; &plusmn; &sup2;
+&sup3; &acute;
+&micro; &para; &middot; &cedil; &sup1; &ordm; &raquo; &frac14; &frac12;
+&frac34; &iquest; &Agrave; &Aacute; &Acirc; &Atilde; &Auml; &Aring;
+&AElig;
+&Ccedil; &Egrave; &Eacute; &Ecirc; &Euml; &Igrave; &Iacute; &Icirc;
+&Iuml; &ETH; &Ntilde; &Ograve; &Oacute; &Ocirc; &Otilde; &Ouml; &times;
+&Oslash;
+&Ugrave; &Uacute; &Ucirc; &Uuml; &Yacute; &THORN; &szlig; &agrave;
+&aacute; &acirc; &atilde; &auml; &aring; &aelig; &ccedil; &egrave;
+&eacute; &ecirc;
+&euml; &igrave; &iacute; &icirc; &iuml; &eth; &ntilde; &ograve; &oacute;
+ &ocirc; &otilde; &ouml; &divide; &oslash; &ugrave; &uacute; &ucirc;
+&uuml; &yacute;
+&thorn; &yuml; </p>
+<p>symbols, math.. ƒ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ ΠΞ Ο Π Ρ Σ Τ Υ
+Φ Χ Ψ Ω α β γ δ ε ζ η θ ι κ λ μ ν ξ ο Ï€ Ï Ï‚
+σ τ υ φ χ ψ ω ϑ ϒ ϖ • … ′ ″ ‾ ℠℘ ℑ ℜ
+™ ℵ ↠↑ → ↓ ↔ ↵ ⇠⇑ ⇒ ⇓ ⇔ ∀ ∂ ∃ ∅ ∇ ∈ ∉
+∋ ∠∑ − ∗ √ ∠∞ ∠ ∧ ∨ ∩ ∪ ∫ ∴ ∼ ≅ ≈ ≠ ≡ ≤ ≥
+⊂ ⊃ ⊄ ⊆ ⊇ ⊕ ⊗ ⊥ ⋅ ⌈ ⌉ ⌊ ⌋ ⟨ ⟩ ◊ ♠ ♣ ♥ ♦
+</p>
+<p> others
+Å’ Å“ Å  Å¡ Ÿ ˆ Ëœ       ‌ †‎ â€â€“— ‘ ’
+‚“ †„ † ‡ ‰ ‹ › €
+</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/file_youtube_flash_embed.html b/dom/base/test/file_youtube_flash_embed.html
new file mode 100644
index 0000000000..0eb63477f4
--- /dev/null
+++ b/dom/base/test/file_youtube_flash_embed.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1240471
+ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1240471</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ let SimpleTest = {
+ finish() {
+ parent.postMessage(JSON.stringify({fn: "finish"}), "*");
+ }
+ };
+ ["ok", "is", "info"].forEach(fn => {
+ self[fn] = function (...args) {
+ parent.postMessage(JSON.stringify({fn, args}), "*");
+ }
+ });
+ "use strict";
+ function onLoad() {
+ let youtube_changed_url_query = "https://mochitest.youtube.com/embed/Xm5i5kbIXzc?start=10&end=20";
+
+ function testEmbed(embed, expected_url, expected_fullscreen) {
+ ok (!!embed, "Embed node exists");
+ // getSVGDocument will return HTMLDocument if the content is HTML
+ let doc = embed.getSVGDocument();
+ // doc must be unprivileged because privileged doc will always be
+ // allowed to use fullscreen.
+ is (doc.fullscreenEnabled, expected_fullscreen,
+ "fullscreen should be " + (expected_fullscreen ? "enabled" : "disabled"));
+ embed = SpecialPowers.wrap(embed);
+ is (embed.srcURI.spec, expected_url, "Should have src uri of " + expected_url);
+ }
+ info("Running youtube rewrite query test");
+ testEmbed(document.getElementById("testembed-correct"), youtube_changed_url_query, false);
+ testEmbed(document.getElementById("testembed-correct-fs"), youtube_changed_url_query, true);
+ testEmbed(document.getElementById("testembed-wrong"), youtube_changed_url_query, false);
+ testEmbed(document.getElementById("testembed-whywouldyouevendothat"), youtube_changed_url_query, true);
+ SimpleTest.finish();
+ }
+ </script>
+ </head>
+ <body onload="onLoad()">
+ <embed id="testembed-correct"
+ src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
+ type="application/x-shockwave-flash"
+ allowscriptaccess="always"></embed>
+ <embed id="testembed-correct-fs"
+ src="https://mochitest.youtube.com/v/Xm5i5kbIXzc?start=10&end=20"
+ type="application/x-shockwave-flash"
+ allowfullscreen
+ allowscriptaccess="always"></embed>
+ <embed id="testembed-wrong"
+ src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10&end=20"
+ type="application/x-shockwave-flash"
+ allowscriptaccess="always"></embed>
+ <embed id="testembed-whywouldyouevendothat"
+ src="https://mochitest.youtube.com/v/Xm5i5kbIXzc&start=10?end=20"
+ type="application/x-shockwave-flash"
+ allowfullscreen
+ allowscriptaccess="always"></embed>
+ </body>
+</html>
diff --git a/dom/base/test/fmm/browser.ini b/dom/base/test/fmm/browser.ini
new file mode 100644
index 0000000000..19f9b584e4
--- /dev/null
+++ b/dom/base/test/fmm/browser.ini
@@ -0,0 +1 @@
+[browser_frame_message_manager_cache.js]
diff --git a/dom/base/test/fmm/browser_frame_message_manager_cache.js b/dom/base/test/fmm/browser_frame_message_manager_cache.js
new file mode 100644
index 0000000000..fcedd6721a
--- /dev/null
+++ b/dom/base/test/fmm/browser_frame_message_manager_cache.js
@@ -0,0 +1,23 @@
+add_task(async function testCacheAfterInvalidate() {
+ // Load some page to make scripts cached.
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "about:addons"
+ );
+
+ // Discard ScriptPreloader cache.
+ Services.obs.notifyObservers(null, "startupcache-invalidate");
+
+ // Load some other page to use the cache in nsMessageManagerScriptExecutor
+ // cache.
+ let tab2 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "about:preferences"
+ );
+
+ // Verify the browser doesn't crash.
+ ok(true);
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+});
diff --git a/dom/base/test/forRemoval.resource b/dom/base/test/forRemoval.resource
new file mode 100644
index 0000000000..09e882b3ba
--- /dev/null
+++ b/dom/base/test/forRemoval.resource
@@ -0,0 +1,24 @@
+:this file must be enconded in utf8
+:and its Content-Type must be equal to text/event-stream
+
+retry:500
+event: message
+data: 1
+
+retry:500
+event: message
+data: 2
+
+retry:500
+event: message
+data: 3
+
+retry:500
+event: message
+data: 4
+
+retry:500
+event: message
+data: 5
+
+
diff --git a/dom/base/test/forRemoval.resource^headers^ b/dom/base/test/forRemoval.resource^headers^
new file mode 100644
index 0000000000..6a63b5341d
--- /dev/null
+++ b/dom/base/test/forRemoval.resource^headers^
@@ -0,0 +1,3 @@
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate
+
diff --git a/dom/base/test/formReset.html b/dom/base/test/formReset.html
new file mode 100644
index 0000000000..faee1e5b4d
--- /dev/null
+++ b/dom/base/test/formReset.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/REC-html401-19991224/strict.dtd">
+<html>
+ <head>
+ <title>Form Elements</title>
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ </head>
+ <body>
+ <p>Check me! <input type="checkbox" id="checkbox1"><br>
+ Uncheck me! <input type="checkbox" checked id="checkbox2"><br>
+ <input type="text" size=30 value="Write something here" id="textinput"><br>
+ <textarea id="textarea">Write something here</textarea><br>
+ </p>
+ </body>
+</html>
diff --git a/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml b/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml
new file mode 100644
index 0000000000..93f00311e7
--- /dev/null
+++ b/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml
@@ -0,0 +1,108 @@
+<?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"?>
+<!--
+ Test that "MozDOMFullscreen:*" events are dispatched to chrome on documents that use DOM fullscreen.
+
+ Test Description:
+
+ This chrome window has a browser. The browser's contentDocument (the "outer document")
+ in turn has an iframe (the "inner document").
+
+ We request fullscreen in the outer document, and check that MozDOMFullscreen:Entered and
+ MozDOMFullscreen:NewOrigin are dispatched to chrome, targeted at the outer document.
+
+ Then we request fullscreen in the inner document, and check that MozDOMFullscreen:NewOrigin
+ is dispatched to chrome, targeted at the inner document.
+
+ Then we cancel fullscreen in the inner document, and check that MozDOMFullscreen:NewOrigin is
+ dispatched again to chrome, targeted at the outer document.
+-->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="start();">
+
+<script src="chrome://mochikit/content/chrome-harness.js"></script>
+<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript"><![CDATA[
+
+function ok(condition, msg) {
+ window.arguments[0].ok(condition, msg);
+}
+
+function is(a, b, msg) {
+ window.arguments[0].is(a, b, msg);
+}
+
+var gBrowser = null;
+var gOuterDoc = null;
+var gInnerDoc = null;
+
+var gReceivedFullscreenEnteredEvent = false;
+function firstEntry(event) {
+ if (event.type == "MozDOMFullscreen:NewOrigin") {
+ ok(false, "MozDOMFullscreen:NewOrigin shouldn't be triggered at first entry");
+ return;
+ }
+
+ if (event.type != "MozDOMFullscreen:Entered") {
+ ok(false, "Unknown event received");
+ return;
+ }
+
+ ok(gOuterDoc.fullscreenElement != null, "Outer doc should be in fullscreen");
+ is(event.target, gOuterDoc.body, "First MozDOMFullscreen:Entered should be targeted at outer body");
+ ok(!gReceivedFullscreenEnteredEvent, "MozDOMFullscreen:Entered shouldn't have been triggered twice");
+ gReceivedFullscreenEnteredEvent = true;
+ window.removeEventListener("MozDOMFullscreen:Entered", firstEntry);
+ window.removeEventListener("MozDOMFullscreen:NewOrigin", firstEntry);
+
+ window.addEventListener("MozDOMFullscreen:NewOrigin", secondEntry);
+ gInnerDoc = gOuterDoc.getElementById("innerFrame").contentDocument;
+ gInnerDoc.defaultView.focus();
+ gInnerDoc.body.requestFullscreen();
+}
+
+function secondEntry(event) {
+ is(event.target, gInnerDoc, "Second MozDOMFullscreen:NewOrigin should be targeted at inner doc");
+ ok(gInnerDoc.fullscreenElement != null, "Inner doc should be in fullscreen");
+ window.removeEventListener("MozDOMFullscreen:NewOrigin", secondEntry);
+ window.addEventListener("MozDOMFullscreen:NewOrigin", thirdEntry);
+ gInnerDoc.exitFullscreen();
+}
+
+function thirdEntry(event) {
+ is(event.target, gOuterDoc, "Third MozDOMFullscreen:NewOrigin should be targeted at outer doc");
+ ok(gOuterDoc.fullscreenElement != null, "Outer doc return to fullscreen after cancel fullscreen in inner doc");
+ window.removeEventListener("MozDOMFullscreen:NewOrigin", thirdEntry);
+ window.removeEventListener("MozDOMFullscreen:Exited", earlyExit);
+ window.addEventListener("MozDOMFullscreen:Exited", lastExit);
+ gOuterDoc.exitFullscreen();
+}
+
+function earlyExit(event) {
+ ok(false, "MozDOMFullscreen:Exited should only be triggered after cancel all fullscreen");
+}
+
+function lastExit(event) {
+ is(event.target, gOuterDoc, "MozDOMFullscreen:Exited should be targeted at the last exited doc");
+ ok(gOuterDoc.fullscreenElement == null, "Fullscreen should have been fully exited");
+ window.arguments[0].done();
+}
+
+function start() {
+ SimpleTest.waitForFocus(
+ function() {
+ gBrowser = document.getElementById("browser");
+ gOuterDoc = gBrowser.contentDocument;
+ gBrowser.contentWindow.focus();
+ window.addEventListener("MozDOMFullscreen:Entered", firstEntry);
+ window.addEventListener("MozDOMFullscreen:NewOrigin", firstEntry);
+ gOuterDoc.body.requestFullscreen();
+ });
+}
+
+]]>
+</script>
+<browser type="content" id="browser" width="400" height="400" src="file_MozDomFullscreen.html"/>
+
+</window>
diff --git a/dom/base/test/fullscreen/browser.ini b/dom/base/test/fullscreen/browser.ini
new file mode 100644
index 0000000000..c472e09b5c
--- /dev/null
+++ b/dom/base/test/fullscreen/browser.ini
@@ -0,0 +1,40 @@
+[DEFAULT]
+tags = fullscreen
+head = head.js
+support-files =
+ dummy_page.html
+ file_fullscreen-api-keys.html
+ file_fullscreen-iframe-inner.html
+ file_fullscreen-iframe-middle.html
+ file_fullscreen-iframe-top.html
+ file_fullscreen-newtab.html
+ fullscreen_helpers.js
+
+[browser_fullscreen-api-keys.js]
+[browser_fullscreen-document-mutation.js]
+[browser_fullscreen-document-mutation-navigation.js]
+[browser_fullscreen-document-mutation-race.js]
+[browser_fullscreen-contextmenu-esc.js]
+[browser_fullscreen-navigation.js]
+skip-if =
+ os == "win" && os_version == "6.1" # Skip on Azure - frequent failure
+[browser_fullscreen-navigation-history.js]
+[browser_fullscreen-navigation-race.js]
+[browser_fullscreen-newtab.js]
+skip-if =
+ os == 'mac' # Bug 1494843
+ os == 'linux' && bits == 64 && os_version == '18.04' # Bug 1601460
+ os == "win" && os_version == "6.1" # Skip on Azure - frequent failure
+[browser_fullscreen-tab-close.js]
+[browser_fullscreen-tab-close-race.js]
+skip-if = !fission # Bug 1750901
+[browser_fullscreen-bug-1798219.js]
+skip-if =
+ !fission
+ !nightly_build # Bug 1818608
+support-files =
+ file_fullscreen-bug-1798219.html
+ file_fullscreen-bug-1798219-2.html
+[browser_fullscreen-window-open-race.js]
+[browser_fullscreen-sizemode.js]
+[browser_fullscreen_exit_on_external_protocol.js]
diff --git a/dom/base/test/fullscreen/browser_fullscreen-api-keys.js b/dom/base/test/fullscreen/browser_fullscreen-api-keys.js
new file mode 100644
index 0000000000..1b1a07975e
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-api-keys.js
@@ -0,0 +1,218 @@
+"use strict";
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+/** Test for Bug 545812 **/
+
+// List of key codes which should exit full-screen mode.
+const kKeyList = [
+ { key: "Escape", keyCode: "VK_ESCAPE", suppressed: true },
+ { key: "F11", keyCode: "VK_F11", suppressed: false },
+];
+
+function receiveExpectedKeyEvents(aBrowser, aKeyCode, aTrusted) {
+ return SpecialPowers.spawn(
+ aBrowser,
+ [aKeyCode, aTrusted],
+ (keyCode, trusted) => {
+ return new Promise(resolve => {
+ let events = trusted
+ ? ["keydown", "keyup"]
+ : ["keydown", "keypress", "keyup"];
+ if (trusted && keyCode == content.wrappedJSObject.KeyEvent.DOM_VK_F11) {
+ // trusted `F11` key shouldn't be fired because of reserved when it's
+ // a shortcut key for exiting from the full screen mode.
+ events.shift();
+ }
+ function listener(event) {
+ let expected = events.shift();
+ Assert.equal(
+ event.type,
+ expected,
+ `Should receive a ${expected} event`
+ );
+ Assert.equal(
+ event.keyCode,
+ keyCode,
+ `Should receive the event with key code ${keyCode}`
+ );
+ if (!events.length) {
+ content.document.removeEventListener("keydown", listener, true);
+ content.document.removeEventListener("keyup", listener, true);
+ content.document.removeEventListener("keypress", listener, true);
+ resolve();
+ }
+ }
+
+ content.document.addEventListener("keydown", listener, true);
+ content.document.addEventListener("keyup", listener, true);
+ content.document.addEventListener("keypress", listener, true);
+ });
+ }
+ );
+}
+
+const kPage =
+ "https://example.org/browser/" +
+ "dom/base/test/fullscreen/file_fullscreen-api-keys.html";
+
+add_task(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"]
+ );
+
+ let tab = BrowserTestUtils.addTab(gBrowser, kPage);
+ let browser = tab.linkedBrowser;
+ gBrowser.selectedTab = tab;
+ registerCleanupFunction(() => gBrowser.removeTab(tab));
+ await waitForDocLoadComplete();
+
+ // Wait for the document being activated, so that
+ // fullscreen request won't be denied.
+ await SpecialPowers.spawn(browser, [], () => {
+ return ContentTaskUtils.waitForCondition(
+ () => content.browsingContext.isActive && content.document.hasFocus(),
+ "document is active"
+ );
+ });
+
+ // Register listener to capture unexpected events
+ let keyEventsCount = 0;
+ let fullScreenEventsCount = 0;
+ let removeFullScreenListener = BrowserTestUtils.addContentEventListener(
+ browser,
+ "fullscreenchange",
+ () => fullScreenEventsCount++
+ );
+ let removeKeyDownListener = BrowserTestUtils.addContentEventListener(
+ browser,
+ "keydown",
+ () => keyEventsCount++,
+ { wantUntrusted: true }
+ );
+ let removeKeyPressListener = BrowserTestUtils.addContentEventListener(
+ browser,
+ "keypress",
+ () => keyEventsCount++,
+ { wantUntrusted: true }
+ );
+ let removeKeyUpListener = BrowserTestUtils.addContentEventListener(
+ browser,
+ "keyup",
+ () => keyEventsCount++,
+ { wantUntrusted: true }
+ );
+
+ let expectedFullScreenEventsCount = 0;
+ let expectedKeyEventsCount = 0;
+
+ for (let { key, keyCode, suppressed } of kKeyList) {
+ let keyCodeValue = KeyEvent["DOM_" + keyCode];
+ info(`Test keycode ${key} (${keyCodeValue})`);
+
+ info("Enter fullscreen");
+ let state = new Promise(resolve => {
+ let removeFun = BrowserTestUtils.addContentEventListener(
+ browser,
+ "fullscreenchange",
+ async () => {
+ removeFun();
+ resolve(
+ await SpecialPowers.spawn(browser, [], () => {
+ return !!content.document.fullscreenElement;
+ })
+ );
+ }
+ );
+ });
+ // request fullscreen
+ SpecialPowers.spawn(browser, [], () => {
+ content.document.body.requestFullscreen();
+ });
+ ok(await state, "The content should have entered fullscreen");
+ ok(document.fullscreenElement, "The chrome should also be in fullscreen");
+
+ is(
+ fullScreenEventsCount,
+ ++expectedFullScreenEventsCount,
+ "correct number of fullscreen events occurred"
+ );
+
+ info("Dispatch untrusted key events from content");
+ let promiseExpectedKeyEvents = receiveExpectedKeyEvents(
+ browser,
+ keyCodeValue,
+ false
+ );
+
+ SpecialPowers.spawn(browser, [keyCode], keyCodeChild => {
+ var evt = new content.CustomEvent("Test:DispatchKeyEvents", {
+ detail: Cu.cloneInto({ code: keyCodeChild }, content),
+ });
+ content.dispatchEvent(evt);
+ });
+ await promiseExpectedKeyEvents;
+
+ expectedKeyEventsCount += 3;
+ is(
+ keyEventsCount,
+ expectedKeyEventsCount,
+ "correct number of key events occurred"
+ );
+
+ info("Send trusted key events");
+
+ state = new Promise(resolve => {
+ let removeFun = BrowserTestUtils.addContentEventListener(
+ browser,
+ "fullscreenchange",
+ async () => {
+ removeFun();
+ resolve(
+ await SpecialPowers.spawn(browser, [], () => {
+ return !!content.document.fullscreenElement;
+ })
+ );
+ }
+ );
+ });
+
+ promiseExpectedKeyEvents = suppressed
+ ? Promise.resolve()
+ : receiveExpectedKeyEvents(browser, keyCodeValue, true);
+ await SpecialPowers.spawn(browser, [], () => {});
+
+ EventUtils.synthesizeKey("KEY_" + key);
+ await promiseExpectedKeyEvents;
+
+ ok(!(await state), "The content should have exited fullscreen");
+ ok(
+ !document.fullscreenElement,
+ "The chrome should also have exited fullscreen"
+ );
+
+ is(
+ fullScreenEventsCount,
+ ++expectedFullScreenEventsCount,
+ "correct number of fullscreen events occurred"
+ );
+ if (!suppressed) {
+ expectedKeyEventsCount += keyCode == "VK_F11" ? 1 : 3;
+ }
+ is(
+ keyEventsCount,
+ expectedKeyEventsCount,
+ "correct number of key events occurred"
+ );
+ }
+
+ removeFullScreenListener();
+ removeKeyDownListener();
+ removeKeyPressListener();
+ removeKeyUpListener();
+});
diff --git a/dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js b/dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js
new file mode 100644
index 0000000000..2aef23b042
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js
@@ -0,0 +1,127 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Import helpers
+/* import-globals-from fullscreen_helpers.js */
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error, https://bugzilla.mozilla.org/show_bug.cgi?id=1742890.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+async function waitAndCheckFullscreenState(aWindow) {
+ // Wait fullscreen exit event if browser is still in fullscreen mode.
+ if (
+ aWindow.fullScreen ||
+ aWindow.document.documentElement.hasAttribute("inFullscreen")
+ ) {
+ info("The widget is still in fullscreen, wait again");
+ await waitWidgetFullscreenEvent(aWindow, false, true);
+ }
+ if (aWindow.document.documentElement.hasAttribute("inDOMFullscreen")) {
+ info("The chrome document is still in fullscreen, wait again");
+ await waitForFullScreenObserver(aWindow, false, true);
+ }
+
+ // Ensure the browser exits fullscreen state.
+ ok(!aWindow.fullScreen, "The widget should not be in fullscreen");
+ ok(
+ !aWindow.document.documentElement.hasAttribute("inFullscreen"),
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !aWindow.document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+}
+
+add_task(async () => {
+ const URL =
+ "http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html";
+ // We need this dummy tab which load the same URL as test tab to keep the
+ // original content process alive after test page navigates away.
+ let dummyTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: URL,
+ },
+ async function (browser) {
+ await SpecialPowers.spawn(browser, [], function () {
+ content.document.querySelector("button").click();
+ });
+
+ // Test requests fullscreen and performs navigation simultaneously,
+ // the fullscreen request might be rejected directly if navigation happens
+ // first, so there might be no reliable state that we can wait. So give
+ // some time for possible fullscreen transition instead and ensure window
+ // should end up exiting fullscreen.
+ await new Promise(aResolve => {
+ SimpleTest.executeSoon(() => {
+ SimpleTest.executeSoon(aResolve);
+ });
+ });
+ await waitAndCheckFullscreenState(window);
+ }
+ );
+
+ let dummyTabClosed = BrowserTestUtils.waitForTabClosing(dummyTab);
+ BrowserTestUtils.removeTab(dummyTab);
+ await dummyTabClosed;
+});
+
+add_task(async () => {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: "http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html",
+ },
+ async function (browser) {
+ // Open a new window to run the tests, the original window will keep the
+ // original content process alive after the test window navigates away.
+ let promiseWin = BrowserTestUtils.waitForNewWindow();
+ await SpecialPowers.spawn(browser, [], function () {
+ content.document.querySelector("button").click();
+ });
+ let newWindow = await promiseWin;
+
+ await SpecialPowers.spawn(
+ newWindow.gBrowser.selectedTab.linkedBrowser,
+ [],
+ function () {
+ content.document.querySelector("button").click();
+ }
+ );
+
+ // Test requests fullscreen and performs navigation simultaneously,
+ // the fullscreen request might be rejected directly if navigation happens
+ // first, so there might be no reliable state that we can wait. So give
+ // some time for possible fullscreen transition instead and ensure window
+ // should end up exiting fullscreen.
+ await new Promise(aResolve => {
+ SimpleTest.executeSoon(() => {
+ SimpleTest.executeSoon(aResolve);
+ });
+ });
+ await waitAndCheckFullscreenState(newWindow);
+
+ newWindow.close();
+ }
+ );
+});
diff --git a/dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js b/dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js
new file mode 100644
index 0000000000..e89409a90f
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js
@@ -0,0 +1,128 @@
+"use strict";
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+function captureUnexpectedFullscreenChange() {
+ ok(false, "Caught an unexpected fullscreen change");
+}
+
+const kPage =
+ "https://example.org/browser/dom/base/test/fullscreen/dummy_page.html";
+
+function waitForDocActivated(aBrowser) {
+ return SpecialPowers.spawn(aBrowser, [], () => {
+ return ContentTaskUtils.waitForCondition(
+ () => content.browsingContext.isActive && content.document.hasFocus()
+ );
+ });
+}
+
+add_task(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"]
+ );
+
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ opening: kPage,
+ waitForStateStop: true,
+ });
+ let browser = tab.linkedBrowser;
+
+ // As requestFullscreen checks the active state of the docshell,
+ // wait for the document to be activated, just to be sure that
+ // the fullscreen request won't be denied.
+ await SpecialPowers.spawn(browser, [], () => {
+ return ContentTaskUtils.waitForCondition(
+ () => content.browsingContext.isActive && content.document.hasFocus()
+ );
+ });
+
+ let contextMenu = document.getElementById("contentAreaContextMenu");
+ ok(contextMenu, "Got context menu");
+
+ let state;
+ info("Enter DOM fullscreen");
+ let fullScreenChangedPromise = BrowserTestUtils.waitForContentEvent(
+ browser,
+ "fullscreenchange"
+ );
+ await SpecialPowers.spawn(browser, [], () => {
+ content.document.body.requestFullscreen();
+ });
+
+ await fullScreenChangedPromise;
+ state = await SpecialPowers.spawn(browser, [], () => {
+ return !!content.document.fullscreenElement;
+ });
+ ok(state, "The content should have entered fullscreen");
+ ok(document.fullscreenElement, "The chrome should also be in fullscreen");
+
+ let removeContentEventListener = BrowserTestUtils.addContentEventListener(
+ browser,
+ "fullscreenchange",
+ captureUnexpectedFullscreenChange
+ );
+
+ info("Open context menu");
+ is(contextMenu.state, "closed", "Should not have opened context menu");
+
+ let popupShownPromise = promiseWaitForEvent(window, "popupshown");
+
+ EventUtils.synthesizeMouse(
+ browser,
+ screen.width / 2,
+ screen.height / 2,
+ { type: "contextmenu", button: 2 },
+ window
+ );
+ await popupShownPromise;
+ is(contextMenu.state, "open", "Should have opened context menu");
+
+ let popupHidePromise = promiseWaitForEvent(window, "popuphidden");
+
+ if (
+ !AppConstants.platform == "macosx" ||
+ !Services.prefs.getBoolPref("widget.macos.native-context-menus", false)
+ ) {
+ info("Send the first escape");
+ EventUtils.synthesizeKey("KEY_Escape");
+ } else {
+ // We cannot synthesize key events at native macOS menus.
+ // We also do not see key events that are processed by native macOS menus,
+ // so we cannot accidentally exit fullscreen when the user closes a native
+ // menu with Escape.
+ // Close the menu normally.
+ info("Close the context menu");
+ contextMenu.hidePopup();
+ }
+ await popupHidePromise;
+ is(contextMenu.state, "closed", "Should have closed context menu");
+
+ // Wait a small time to confirm that the first ESC key
+ // does not exit fullscreen.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ state = await SpecialPowers.spawn(browser, [], () => {
+ return !!content.document.fullscreenElement;
+ });
+ ok(state, "The content should still be in fullscreen");
+ ok(document.fullscreenElement, "The chrome should still be in fullscreen");
+
+ removeContentEventListener();
+ info("Send the second escape");
+ let fullscreenExitPromise = BrowserTestUtils.waitForContentEvent(
+ browser,
+ "fullscreenchange"
+ );
+ EventUtils.synthesizeKey("KEY_Escape");
+ await fullscreenExitPromise;
+ ok(!document.fullscreenElement, "The chrome should have exited fullscreen");
+
+ gBrowser.removeTab(tab);
+});
diff --git a/dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js
new file mode 100644
index 0000000000..f6b5715f59
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js
@@ -0,0 +1,141 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+async function startTests(testFun, name) {
+ TEST_URLS.forEach(url => {
+ add_task(async () => {
+ info(`Test ${name}, url: ${url}`);
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ let promiseFsState = waitForFullscreenState(document, true);
+ // Trigger click event in inner most iframe
+ SpecialPowers.spawn(
+ browser.browsingContext.children[0].children[0],
+ [],
+ function () {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ }
+ );
+ await promiseFsState;
+
+ // This should exit fullscreen
+ promiseFsState = waitForFullscreenState(document, false, true);
+ await testFun(browser);
+ await promiseFsState;
+
+ // This test triggers a fullscreen request during the fullscreen exit
+ // process, so it could be possible that the widget or the chrome
+ // document goes into fullscreen mode again, but they should end up
+ // leaving fullscreen mode again.
+ if (
+ window.fullScreen ||
+ document.documentElement.hasAttribute("inFullscreen")
+ ) {
+ info("widget is still in fullscreen, wait again");
+ await waitWidgetFullscreenEvent(window, false, true);
+ }
+ if (document.documentElement.hasAttribute("inDOMFullscreen")) {
+ info("chrome document is still in fullscreen, wait again");
+ await waitForFullScreenObserver(document, false, true);
+ }
+
+ // Ensure the browser exits fullscreen state.
+ ok(!window.fullScreen, "The widget should not be in fullscreen");
+ ok(
+ !document.documentElement.hasAttribute("inFullscreen"),
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+ });
+ });
+}
+
+function MutateAndNavigateFromRemoteDocument(
+ aBrowsingContext,
+ aElementId,
+ aURL
+) {
+ return SpecialPowers.spawn(
+ aBrowsingContext,
+ [aElementId, aURL],
+ async function (id, url) {
+ let element = content.document.getElementById(id);
+ element.requestFullscreen();
+ content.document.body.appendChild(element);
+ content.location.href = url;
+ }
+ );
+}
+
+startTests(async browser => {
+ // toplevel
+ await MutateAndNavigateFromRemoteDocument(
+ browser.browsingContext,
+ "div",
+ "about:blank"
+ );
+}, "document_mutation_navigation_toplevel");
+
+startTests(async browser => {
+ let promiseRemoteFsState = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ ]);
+ // middle iframe
+ await MutateAndNavigateFromRemoteDocument(
+ browser.browsingContext.children[0],
+ "div",
+ "about:blank"
+ );
+ await promiseRemoteFsState;
+}, "document_mutation_navigation_middle_frame");
+
+startTests(async browser => {
+ let promiseRemoteFsState = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ [browser.browsingContext.children[0], "middle"],
+ ]);
+ // innermost iframe
+ await MutateAndNavigateFromRemoteDocument(
+ browser.browsingContext.children[0].children[0],
+ "div",
+ "about:blank"
+ );
+ await promiseRemoteFsState;
+}, "document_mutation_navigation_inner_frame");
diff --git a/dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js
new file mode 100644
index 0000000000..75ca199aaa
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js
@@ -0,0 +1,122 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+async function startTests(setupFun, name) {
+ TEST_URLS.forEach(url => {
+ add_task(async () => {
+ info(`Test ${name}, url: ${url}`);
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ let promiseFsState = Promise.all([
+ setupFun(browser),
+ waitForFullscreenState(document, false, true),
+ ]);
+ // Trigger click event in inner most iframe
+ SpecialPowers.spawn(
+ browser.browsingContext.children[0].children[0],
+ [],
+ function () {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ }
+ );
+ await promiseFsState;
+
+ // Ensure the browser exits fullscreen state.
+ ok(
+ !window.fullScreen,
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+ });
+ });
+}
+
+function RemoveElementFromRemoteDocument(aBrowsingContext, aElementId) {
+ return SpecialPowers.spawn(
+ aBrowsingContext,
+ [aElementId],
+ async function (id) {
+ content.document.addEventListener(
+ "fullscreenchange",
+ function () {
+ content.document.getElementById(id).remove();
+ },
+ { once: true }
+ );
+ }
+ );
+}
+
+startTests(async browser => {
+ // toplevel
+ let promise = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ ]);
+ await RemoveElementFromRemoteDocument(browser.browsingContext, "div");
+ return promise;
+}, "document_mutation_toplevel");
+
+startTests(async browser => {
+ // middle iframe
+ let promise = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ [browser.browsingContext.children[0], "middle"],
+ ]);
+ await RemoveElementFromRemoteDocument(
+ browser.browsingContext.children[0],
+ "div"
+ );
+ return promise;
+}, "document_mutation_middle_frame");
+
+startTests(async browser => {
+ // innermost iframe
+ let promise = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ [browser.browsingContext.children[0], "middle"],
+ [browser.browsingContext.children[0].children[0], "inner"],
+ ]);
+ await RemoveElementFromRemoteDocument(
+ browser.browsingContext.children[0].children[0],
+ "div"
+ );
+ return promise;
+}, "document_mutation_inner_frame");
diff --git a/dom/base/test/fullscreen/browser_fullscreen-document-mutation.js b/dom/base/test/fullscreen/browser_fullscreen-document-mutation.js
new file mode 100644
index 0000000000..7cecdabb95
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-document-mutation.js
@@ -0,0 +1,118 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+async function startTests(testFun, name) {
+ TEST_URLS.forEach(url => {
+ add_task(async () => {
+ info(`Test ${name}, url: ${url}`);
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ let promiseFsState = waitForFullscreenState(document, true);
+ // Trigger click event in inner most iframe
+ SpecialPowers.spawn(
+ browser.browsingContext.children[0].children[0],
+ [],
+ function () {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ }
+ );
+ await promiseFsState;
+
+ // This should exit fullscreen
+ promiseFsState = waitForFullscreenState(document, false);
+ await testFun(browser);
+ await promiseFsState;
+
+ // Ensure the browser exits fullscreen state.
+ ok(
+ !window.fullScreen,
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+ });
+ });
+}
+
+function RemoveElementFromRemoteDocument(aBrowsingContext, aElementId) {
+ return SpecialPowers.spawn(
+ aBrowsingContext,
+ [aElementId],
+ async function (id) {
+ content.document.getElementById(id).remove();
+ }
+ );
+}
+
+startTests(async browser => {
+ let promiseRemoteFsState = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ ]);
+ // toplevel
+ await RemoveElementFromRemoteDocument(browser.browsingContext, "div");
+ await promiseRemoteFsState;
+}, "document_mutation_toplevel");
+
+startTests(async browser => {
+ let promiseRemoteFsState = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ [browser.browsingContext.children[0], "middle"],
+ ]);
+ // middle iframe
+ await RemoveElementFromRemoteDocument(
+ browser.browsingContext.children[0],
+ "div"
+ );
+ await promiseRemoteFsState;
+}, "document_mutation_middle_frame");
+
+startTests(async browser => {
+ let promiseRemoteFsState = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ [browser.browsingContext.children[0], "middle"],
+ [browser.browsingContext.children[0].children[0], "inner"],
+ ]);
+ // innermost iframe
+ await RemoveElementFromRemoteDocument(
+ browser.browsingContext.children[0].children[0],
+ "div"
+ );
+ await promiseRemoteFsState;
+}, "document_mutation_inner_frame");
diff --git a/dom/base/test/fullscreen/browser_fullscreen-navigation-history.js b/dom/base/test/fullscreen/browser_fullscreen-navigation-history.js
new file mode 100644
index 0000000000..08624ed327
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-navigation-history.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error, bug 1742890.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+function preventBFCache(aBrowsingContext, aPrevent) {
+ return SpecialPowers.spawn(aBrowsingContext, [aPrevent], prevent => {
+ if (prevent) {
+ // Using a dummy onunload listener to disable the bfcache.
+ content.window.addEventListener("unload", () => {});
+ }
+ content.window.addEventListener(
+ "pagehide",
+ e => {
+ // XXX checking persisted property causes intermittent failures, so we
+ // dump the value instead, bug 1822263.
+ // is(e.persisted, !prevent, `Check BFCache state`);
+ info(`Check BFCache state: e.persisted is ${e.persisted}`);
+ },
+ { once: true }
+ );
+ });
+}
+
+[true, false].forEach(crossOrigin => {
+ [true, false].forEach(initialPagePreventsBFCache => {
+ [true, false].forEach(fullscreenPagePreventsBFCache => {
+ add_task(async function navigation_history() {
+ info(
+ `crossOrigin: ${crossOrigin}, initialPagePreventsBFCache: ${initialPagePreventsBFCache}, fullscreenPagePreventsBFCache: ${fullscreenPagePreventsBFCache}`
+ );
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: "http://mochi.test:8888/browser/dom/base/test/fullscreen/dummy_page.html",
+ },
+ async function (browser) {
+ // Maybe prevent BFCache on initial page.
+ await preventBFCache(
+ browser.browsingContext,
+ initialPagePreventsBFCache
+ );
+
+ // Navigate to fullscreen page.
+ const url = crossOrigin
+ ? "https://example.org/browser/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html"
+ : "http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html";
+ const loaded = BrowserTestUtils.browserLoaded(browser, false, url);
+ BrowserTestUtils.loadURIString(browser, url);
+ await loaded;
+
+ // Maybe prevent BFCache on fullscreen test page.
+ await preventBFCache(
+ browser.browsingContext,
+ fullscreenPagePreventsBFCache
+ );
+
+ // Trigger click event to enter fullscreen.
+ let promiseFsState = waitForFullscreenState(document, true);
+ SpecialPowers.spawn(browser.browsingContext, [], () => {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ });
+ await promiseFsState;
+
+ // Navigate back to the previous page should exit fullscreen.
+ promiseFsState = waitForFullscreenState(document, false);
+ await SpecialPowers.spawn(browser.browsingContext, [], () => {
+ content.window.history.back();
+ });
+ await promiseFsState;
+ }
+ );
+ });
+ });
+ });
+});
diff --git a/dom/base/test/fullscreen/browser_fullscreen-navigation-race.js b/dom/base/test/fullscreen/browser_fullscreen-navigation-race.js
new file mode 100644
index 0000000000..f9d1543a1a
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-navigation-race.js
@@ -0,0 +1,162 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+add_task(async function navigation() {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: `data:text/html,
+ <button id="button">Click here</button>
+ <script>
+ let button = document.getElementById("button");
+ button.addEventListener("click", function() {
+ button.requestFullscreen();
+ location.href = "about:blank";
+ });
+ </script>`,
+ },
+ async function (browser) {
+ BrowserTestUtils.synthesizeMouseAtCenter("#button", {}, browser);
+
+ // Give some time for fullscreen transition.
+ await new Promise(aResolve => {
+ SimpleTest.executeSoon(() => {
+ SimpleTest.executeSoon(aResolve);
+ });
+ });
+
+ // Wait fullscreen exit event if browser is still in fullscreen mode.
+ if (
+ window.fullScreen ||
+ document.documentElement.hasAttribute("inFullscreen")
+ ) {
+ info("The widget is still in fullscreen, wait again");
+ await waitWidgetFullscreenEvent(window, false, true);
+ }
+ if (document.documentElement.hasAttribute("inDOMFullscreen")) {
+ info("The chrome document is still in fullscreen, wait again");
+ await waitForFullScreenObserver(window, false, true);
+ }
+
+ // Ensure the browser exits fullscreen state.
+ ok(!window.fullScreen, "The widget should not be in fullscreen");
+ ok(
+ !document.documentElement.hasAttribute("inFullscreen"),
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+});
+
+async function startTests(setupFun, name) {
+ TEST_URLS.forEach(url => {
+ add_task(async () => {
+ info(`Test ${name}, url: ${url}`);
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ let promiseFsState = Promise.all([
+ setupFun(browser),
+ waitForFullscreenState(document, false, true),
+ ]);
+ // Trigger click event in inner most iframe
+ SpecialPowers.spawn(
+ browser.browsingContext.children[0].children[0],
+ [],
+ function () {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ }
+ );
+ await promiseFsState;
+
+ // Ensure the browser exits fullscreen state.
+ ok(
+ !window.fullScreen,
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+ });
+ });
+}
+
+function NavigateRemoteDocument(aBrowsingContext, aURL) {
+ return SpecialPowers.spawn(aBrowsingContext, [aURL], async function (url) {
+ content.document.addEventListener(
+ "fullscreenchange",
+ function () {
+ content.location.href = url;
+ },
+ { once: true }
+ );
+ });
+}
+
+startTests(async browser => {
+ // toplevel
+ await NavigateRemoteDocument(browser.browsingContext, "about:blank");
+}, "navigation_toplevel");
+
+startTests(async browser => {
+ // middle iframe
+ let promise = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ ]);
+ await NavigateRemoteDocument(
+ browser.browsingContext.children[0],
+ "about:blank"
+ );
+ return promise;
+}, "navigation_middle_frame");
+
+startTests(async browser => {
+ // innermost iframe
+ let promise = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ [browser.browsingContext.children[0], "middle"],
+ ]);
+ await NavigateRemoteDocument(
+ browser.browsingContext.children[0].children[0],
+ "about:blank"
+ );
+ return promise;
+}, "navigation_inner_frame");
diff --git a/dom/base/test/fullscreen/browser_fullscreen-navigation.js b/dom/base/test/fullscreen/browser_fullscreen-navigation.js
new file mode 100644
index 0000000000..02387eb437
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-navigation.js
@@ -0,0 +1,142 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+add_task(async function navigation() {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: `data:text/html,
+ <button id="button">Click here</button>
+ <script>
+ let button = document.getElementById("button");
+ button.addEventListener("click", function() {
+ button.requestFullscreen();
+ });
+ </script>`,
+ },
+ async function (browser) {
+ let promiseFsState = waitForFullscreenState(document, true);
+ // Trigger click event
+ BrowserTestUtils.synthesizeMouseAtCenter("#button", {}, browser);
+ await promiseFsState;
+
+ promiseFsState = waitForFullscreenState(document, false);
+ await SpecialPowers.spawn(browser, [], async function () {
+ content.location.href = "about:blank";
+ });
+ await promiseFsState;
+
+ // Ensure the browser exits fullscreen state.
+ ok(!window.fullScreen, "The chrome window should not be in fullscreen");
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+});
+
+async function startTests(testFun, name) {
+ TEST_URLS.forEach(url => {
+ add_task(async () => {
+ info(`Test ${name}, url: ${url}`);
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ let promiseFsState = waitForFullscreenState(document, true);
+ // Trigger click event in inner most iframe
+ SpecialPowers.spawn(
+ browser.browsingContext.children[0].children[0],
+ [],
+ function () {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ }
+ );
+ await promiseFsState;
+
+ // This should exit fullscreen
+ promiseFsState = waitForFullscreenState(document, false);
+ await testFun(browser);
+ await promiseFsState;
+
+ // Ensure the browser exits fullscreen state.
+ ok(
+ !window.fullScreen,
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+ });
+ });
+}
+
+function NavigateRemoteDocument(aBrowsingContext, aURL) {
+ return SpecialPowers.spawn(aBrowsingContext, [aURL], async function (url) {
+ content.location.href = url;
+ });
+}
+
+startTests(async browser => {
+ // toplevel
+ await NavigateRemoteDocument(browser.browsingContext, "about:blank");
+}, "navigation_toplevel");
+
+startTests(async browser => {
+ let promiseRemoteFsState = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ ]);
+ // middle iframe
+ await NavigateRemoteDocument(
+ browser.browsingContext.children[0],
+ "about:blank"
+ );
+ await promiseRemoteFsState;
+}, "navigation_middle_frame");
+
+startTests(async browser => {
+ let promiseRemoteFsState = waitRemoteFullscreenExitEvents([
+ // browsingContext, name
+ [browser.browsingContext, "toplevel"],
+ [browser.browsingContext.children[0], "middle"],
+ ]);
+ // innermost iframe
+ await NavigateRemoteDocument(
+ browser.browsingContext.children[0].children[0],
+ "about:blank"
+ );
+ await promiseRemoteFsState;
+}, "navigation_inner_frame");
diff --git a/dom/base/test/fullscreen/browser_fullscreen-newtab.js b/dom/base/test/fullscreen/browser_fullscreen-newtab.js
new file mode 100644
index 0000000000..af714b1248
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-newtab.js
@@ -0,0 +1,91 @@
+"use strict";
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+const kPage =
+ "https://example.org/browser/" +
+ "dom/base/test/fullscreen/file_fullscreen-newtab.html";
+
+function getSizeMode() {
+ return document.documentElement.getAttribute("sizemode");
+}
+
+async function runTest() {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: kPage,
+ },
+ async function (browser) {
+ let promiseFsEvents = SpecialPowers.spawn(browser, [], function () {
+ return new Promise(resolve => {
+ let countFsChange = 0;
+ let countFsError = 0;
+ function checkAndResolve() {
+ if (countFsChange > 0 && countFsError > 0) {
+ Assert.ok(
+ false,
+ "Got both fullscreenchange and fullscreenerror events"
+ );
+ } else if (countFsChange > 2) {
+ Assert.ok(false, "Got too many fullscreenchange events");
+ } else if (countFsError > 1) {
+ Assert.ok(false, "Got too many fullscreenerror events");
+ } else if (countFsChange == 2 || countFsError == 1) {
+ resolve();
+ }
+ }
+
+ content.document.addEventListener("fullscreenchange", () => {
+ ++countFsChange;
+ checkAndResolve();
+ });
+ content.document.addEventListener("fullscreenerror", () => {
+ ++countFsError;
+ checkAndResolve();
+ });
+ });
+ });
+ let promiseNewTab = BrowserTestUtils.waitForNewTab(
+ gBrowser,
+ "about:blank"
+ );
+ await BrowserTestUtils.synthesizeMouseAtCenter("#link", {}, browser);
+ let [newtab] = await Promise.all([promiseNewTab, promiseFsEvents]);
+ await BrowserTestUtils.removeTab(newtab);
+
+ // Ensure the browser exits fullscreen state in reasonable time.
+ await Promise.race([
+ BrowserTestUtils.waitForCondition(() => getSizeMode() == "normal"),
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ new Promise(resolve => setTimeout(resolve, 2000)),
+ ]);
+
+ ok(!window.fullScreen, "The chrome window should not be in fullscreen");
+ ok(
+ !document.fullscreen,
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+}
+
+add_task(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"]
+ );
+ await runTest();
+});
+
+add_task(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "200 200"],
+ ["full-screen-api.transition-duration.leave", "200 200"]
+ );
+ await runTest();
+});
diff --git a/dom/base/test/fullscreen/browser_fullscreen-sizemode.js b/dom/base/test/fullscreen/browser_fullscreen-sizemode.js
new file mode 100644
index 0000000000..0aa79e5694
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-sizemode.js
@@ -0,0 +1,225 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const isMac = AppConstants.platform == "macosx";
+const isWin = AppConstants.platform == "win";
+
+async function waitForSizeMode(aWindow, aSizeMode) {
+ await BrowserTestUtils.waitForEvent(aWindow, "sizemodechange", false, () => {
+ return aWindow.windowState === aSizeMode;
+ });
+ const expectedHidden =
+ aSizeMode == aWindow.STATE_MINIMIZED || aWindow.isFullyOccluded;
+ if (aWindow.document.hidden != expectedHidden) {
+ await BrowserTestUtils.waitForEvent(aWindow, "visibilitychange");
+ }
+ is(
+ aWindow.document.hidden,
+ expectedHidden,
+ "Should be inactive if minimized or occluded"
+ );
+}
+
+async function checkSizeModeAndFullscreenState(
+ aWindow,
+ aSizeMode,
+ aFullscreen,
+ aFullscreenEventShouldHaveFired,
+ aStepFun
+) {
+ let promises = [];
+ if (aWindow.windowState != aSizeMode) {
+ promises.push(waitForSizeMode(aWindow, aSizeMode));
+ }
+ if (aFullscreenEventShouldHaveFired) {
+ promises.push(
+ BrowserTestUtils.waitForEvent(
+ aWindow,
+ aFullscreen ? "willenterfullscreen" : "willexitfullscreen"
+ )
+ );
+ promises.push(BrowserTestUtils.waitForEvent(aWindow, "fullscreen"));
+ }
+
+ // Add listener for unexpected event.
+ let unexpectedEventListener = aEvent => {
+ ok(false, `should not receive ${aEvent.type} event`);
+ };
+ if (aFullscreenEventShouldHaveFired) {
+ aWindow.addEventListener(
+ aFullscreen ? "willexitfullscreen" : "willenterfullscreen",
+ unexpectedEventListener
+ );
+ } else {
+ aWindow.addEventListener("willenterfullscreen", unexpectedEventListener);
+ aWindow.addEventListener("willexitfullscreen", unexpectedEventListener);
+ aWindow.addEventListener("fullscreen", unexpectedEventListener);
+ }
+
+ let eventPromise = Promise.all(promises);
+ aStepFun();
+ await eventPromise;
+
+ // Check SizeMode.
+ is(
+ aWindow.windowState,
+ aSizeMode,
+ "The new sizemode should have the expected value"
+ );
+ // Check Fullscreen state.
+ is(
+ aWindow.fullScreen,
+ aFullscreen,
+ `chrome window should ${aFullscreen ? "be" : "not be"} in fullscreen`
+ );
+ is(
+ aWindow.document.documentElement.hasAttribute("inFullscreen"),
+ aFullscreen,
+ `chrome documentElement should ${
+ aFullscreen ? "have" : "not have"
+ } inFullscreen attribute`
+ );
+
+ // Remove listener for unexpected event.
+ if (aFullscreenEventShouldHaveFired) {
+ aWindow.removeEventListener(
+ aFullscreen ? "willexitfullscreen" : "willenterfullscreen",
+ unexpectedEventListener
+ );
+ } else {
+ aWindow.removeEventListener("willenterfullscreen", unexpectedEventListener);
+ aWindow.removeEventListener("willexitfullscreen", unexpectedEventListener);
+ aWindow.removeEventListener("fullscreen", unexpectedEventListener);
+ }
+}
+
+async function restoreWindowToNormal(aWindow) {
+ while (aWindow.windowState != aWindow.STATE_NORMAL) {
+ info(`Try to restore window with state ${aWindow.windowState} to normal`);
+ let eventPromise = BrowserTestUtils.waitForEvent(aWindow, "sizemodechange");
+ aWindow.restore();
+ await eventPromise;
+ info(`Window is now in state ${aWindow.windowState}`);
+ }
+}
+
+add_task(async function test_fullscreen_restore() {
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await restoreWindowToNormal(win);
+
+ info("Enter fullscreen");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_FULLSCREEN,
+ true,
+ true,
+ () => {
+ win.fullScreen = true;
+ }
+ );
+
+ info("Restore window");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_NORMAL,
+ false,
+ true,
+ () => {
+ win.restore();
+ }
+ );
+
+ await BrowserTestUtils.closeWindow(win);
+});
+
+// This test only enable on Windows because:
+// - Test gets intermittent timeout on macOS, see bug 1828848.
+// - Restoring a fullscreen window on GTK doesn't return it to the previous
+// sizemode, see bug 1828837.
+if (isWin) {
+ add_task(async function test_maximize_fullscreen_restore() {
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await restoreWindowToNormal(win);
+
+ info("Maximize window");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_MAXIMIZED,
+ false,
+ false,
+ () => {
+ win.maximize();
+ }
+ );
+
+ info("Enter fullscreen");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_FULLSCREEN,
+ true,
+ true,
+ () => {
+ win.fullScreen = true;
+ }
+ );
+
+ info("Restore window");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_MAXIMIZED,
+ false,
+ true,
+ () => {
+ win.restore();
+ }
+ );
+
+ await BrowserTestUtils.closeWindow(win);
+ });
+}
+
+// Restoring a minimized window on macOS doesn't return it to the previous
+// sizemode, see bug 1828706.
+if (!isMac) {
+ add_task(async function test_fullscreen_minimize_restore() {
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await restoreWindowToNormal(win);
+
+ info("Enter fullscreen");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_FULLSCREEN,
+ true,
+ true,
+ () => {
+ win.fullScreen = true;
+ }
+ );
+
+ info("Minimize window");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_MINIMIZED,
+ true,
+ false,
+ () => {
+ win.minimize();
+ }
+ );
+
+ info("Restore window");
+ await checkSizeModeAndFullscreenState(
+ win,
+ win.STATE_FULLSCREEN,
+ true,
+ false,
+ () => {
+ win.restore();
+ }
+ );
+
+ await BrowserTestUtils.closeWindow(win);
+ });
+}
diff --git a/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js b/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js
new file mode 100644
index 0000000000..f1b300b93a
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js
@@ -0,0 +1,101 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+async function startTests(setupFun, name) {
+ TEST_URLS.forEach(url => {
+ add_task(async () => {
+ info(`Test ${name}, url: ${url}`);
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ let promiseFsState = waitForFullscreenExit(document);
+ setupFun(browser);
+ // Trigger click event in inner most iframe
+ SpecialPowers.spawn(
+ browser.browsingContext.children[0].children[0],
+ [],
+ function () {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ }
+ );
+ await promiseFsState;
+
+ // Ensure the browser exits fullscreen state.
+ ok(
+ !window.fullScreen,
+ "The chrome window should not be in fullscreen"
+ );
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+ });
+ });
+}
+
+async function WaitRemoveDocumentAndCloseTab(aBrowser, aBrowsingContext) {
+ await SpecialPowers.spawn(aBrowsingContext, [], async function () {
+ return new Promise(resolve => {
+ content.document.addEventListener(
+ "fullscreenchange",
+ e => {
+ resolve();
+ },
+ { once: true }
+ );
+ });
+ });
+
+ // This should exit fullscreen
+ let tab = gBrowser.getTabForBrowser(aBrowser);
+ BrowserTestUtils.removeTab(tab);
+}
+
+startTests(async browser => {
+ // toplevel
+ WaitRemoveDocumentAndCloseTab(browser, browser.browsingContext);
+}, "tab_close_toplevel");
+
+startTests(browser => {
+ // middle iframe
+ WaitRemoveDocumentAndCloseTab(browser, browser.browsingContext.children[0]);
+}, "tab_close_middle_frame");
+
+startTests(async browser => {
+ // innermost iframe
+ WaitRemoveDocumentAndCloseTab(
+ browser,
+ browser.browsingContext.children[0].children[0]
+ );
+}, "tab_close_inner_frame");
diff --git a/dom/base/test/fullscreen/browser_fullscreen-tab-close.js b/dom/base/test/fullscreen/browser_fullscreen-tab-close.js
new file mode 100644
index 0000000000..7d1772cd48
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-tab-close.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+TEST_URLS.forEach(url => {
+ add_task(async () => {
+ info(`url: ${url}`);
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ let promiseFsState = waitForFullscreenState(document, true);
+ // Trigger click event in inner most iframe
+ SpecialPowers.spawn(
+ browser.browsingContext.children[0].children[0],
+ [],
+ function () {
+ content.setTimeout(() => {
+ content.document.getElementById("div").click();
+ }, 0);
+ }
+ );
+ await promiseFsState;
+
+ let promiseFsExit = waitForFullscreenExit(document, false);
+ // This should exit fullscreen
+ let tab = gBrowser.getTabForBrowser(browser);
+ BrowserTestUtils.removeTab(tab);
+ await promiseFsExit;
+
+ // Ensure the browser exits fullscreen state.
+ ok(!window.fullScreen, "The chrome window should not be in fullscreen");
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+ }
+ );
+ });
+});
diff --git a/dom/base/test/fullscreen/browser_fullscreen-window-open-race.js b/dom/base/test/fullscreen/browser_fullscreen-window-open-race.js
new file mode 100644
index 0000000000..4cf8a3d8c7
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen-window-open-race.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error, bug 1742890.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+add_task(async () => {
+ const url =
+ "http://mochi.test:8888/browser/dom/base/test/fullscreen/dummy_page.html";
+ const name = "foo";
+
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url,
+ },
+ async function (browser) {
+ info("open new window");
+ SpecialPowers.spawn(browser, [url, name], function (u, n) {
+ content.document.notifyUserGestureActivation();
+ content.window.open(u, n, "width=100,height=100");
+ });
+ let newWin = await BrowserTestUtils.waitForNewWindow({ url });
+ await SimpleTest.promiseFocus(newWin);
+
+ info("re-focusing main window");
+ await SimpleTest.promiseFocus(window);
+
+ info("open an existing window and request fullscreen");
+ await SpecialPowers.spawn(browser, [url, name], function (u, n) {
+ content.document.notifyUserGestureActivation();
+ content.window.open(u, n);
+ content.document.body.requestFullscreen();
+ });
+
+ // We call window.open() first than requestFullscreen() in a row on
+ // content page, but given that focus sync-up takes several IPC exchanges,
+ // so parent process ends up processing the requests in a reverse order,
+ // which should reject the fullscreen request and leave fullscreen.
+ await waitWidgetFullscreenEvent(window, false, true);
+
+ // Ensure the browser exits fullscreen state.
+ ok(!window.fullScreen, "The chrome window should not be in fullscreen");
+ ok(
+ !document.documentElement.hasAttribute("inDOMFullscreen"),
+ "The chrome document should not be in fullscreen"
+ );
+
+ await BrowserTestUtils.closeWindow(newWin);
+ }
+ );
+});
diff --git a/dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js b/dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js
new file mode 100644
index 0000000000..6f525da541
--- /dev/null
+++ b/dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js
@@ -0,0 +1,215 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+SimpleTest.requestCompleteLog();
+
+requestLongerTimeout(2);
+
+// Import helpers
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js",
+ this
+);
+
+add_setup(async function () {
+ await pushPrefs(
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ["full-screen-api.allow-trusted-requests-only", false]
+ );
+});
+
+const { HandlerServiceTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/HandlerServiceTestUtils.sys.mjs"
+);
+
+const gHandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
+ Ci.nsIHandlerService
+);
+
+const CONTENT = `data:text/html,
+ <!DOCTYPE html>
+ <html>
+ <body>
+ <button>
+ <a href="mailto:test@example.com"></a>
+ </button>
+ </body>
+ </html>
+`;
+
+// This test tends to trigger a race in the fullscreen time telemetry,
+// where the fullscreen enter and fullscreen exit events (which use the
+// same histogram ID) overlap. That causes TelemetryStopwatch to log an
+// error.
+SimpleTest.ignoreAllUncaughtExceptions(true);
+
+function setupMailHandler() {
+ let mailHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto");
+ let gOldMailHandlers = [];
+
+ // Remove extant web handlers because they have icons that
+ // we fetch from the web, which isn't allowed in tests.
+ let handlers = mailHandlerInfo.possibleApplicationHandlers;
+ for (let i = handlers.Count() - 1; i >= 0; i--) {
+ try {
+ let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
+ gOldMailHandlers.push(handler);
+ // If we get here, this is a web handler app. Remove it:
+ handlers.removeElementAt(i);
+ } catch (ex) {}
+ }
+
+ let previousHandling = mailHandlerInfo.alwaysAskBeforeHandling;
+ mailHandlerInfo.alwaysAskBeforeHandling = true;
+
+ // Create a dummy web mail handler so we always know the mailto: protocol.
+ // Without this, the test fails on VMs without a default mailto: handler,
+ // because no dialog is ever shown, as we ignore subframe navigations to
+ // protocols that cannot be handled.
+ let dummy = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance(
+ Ci.nsIWebHandlerApp
+ );
+ dummy.name = "Handler 1";
+ dummy.uriTemplate = "https://example.com/first/%s";
+ mailHandlerInfo.possibleApplicationHandlers.appendElement(dummy);
+
+ gHandlerSvc.store(mailHandlerInfo);
+ registerCleanupFunction(() => {
+ // Re-add the original protocol handlers:
+ let mailHandlers = mailHandlerInfo.possibleApplicationHandlers;
+ for (let i = handlers.Count() - 1; i >= 0; i--) {
+ try {
+ // See if this is a web handler. If it is, it'll throw, otherwise,
+ // we will remove it.
+ mailHandlers.queryElementAt(i, Ci.nsIWebHandlerApp);
+ mailHandlers.removeElementAt(i);
+ } catch (ex) {}
+ }
+ for (let h of gOldMailHandlers) {
+ mailHandlers.appendElement(h);
+ }
+ mailHandlerInfo.alwaysAskBeforeHandling = previousHandling;
+ gHandlerSvc.store(mailHandlerInfo);
+ });
+}
+
+add_task(setupMailHandler);
+
+// Fullscreen is canceled during fullscreen transition
+add_task(async function OpenExternalProtocolOnPendingLaterFullscreen() {
+ for (const useClick of [true, false]) {
+ await BrowserTestUtils.withNewTab(CONTENT, async browser => {
+ const leavelFullscreen = waitForFullscreenState(document, false, true);
+ await SpecialPowers.spawn(
+ browser,
+ [useClick],
+ async function (shouldClick) {
+ const button = content.document.querySelector("button");
+
+ const clickDone = new Promise(r => {
+ button.addEventListener(
+ "click",
+ function () {
+ content.document.documentElement.requestFullscreen();
+ // When anchor.click() is called, the fullscreen request
+ // is probably still pending.
+ content.setTimeout(() => {
+ if (shouldClick) {
+ content.document.querySelector("a").click();
+ } else {
+ content.document.location = "mailto:test@example.com";
+ }
+ r();
+ }, 0);
+ },
+ { once: true }
+ );
+ });
+ button.click();
+ await clickDone;
+ }
+ );
+
+ await leavelFullscreen;
+ ok(true, "Fullscreen should be exited");
+ });
+ }
+});
+
+// Fullscreen is canceled immediately.
+add_task(async function OpenExternalProtocolOnPendingFullscreen() {
+ for (const useClick of [true, false]) {
+ await BrowserTestUtils.withNewTab(CONTENT, async browser => {
+ await SpecialPowers.spawn(
+ browser,
+ [useClick],
+ async function (shouldClick) {
+ const button = content.document.querySelector("button");
+
+ const clickDone = new Promise(r => {
+ button.addEventListener(
+ "click",
+ function () {
+ content.document.documentElement
+ .requestFullscreen()
+ .then(() => {
+ ok(false, "Don't enter fullscreen");
+ })
+ .catch(() => {
+ ok(true, "Cancel entering fullscreen");
+ r();
+ });
+ // When anchor.click() is called, the fullscreen request
+ // is probably still pending.
+ if (shouldClick) {
+ content.document.querySelector("a").click();
+ } else {
+ content.document.location = "mailto:test@example.com";
+ }
+ },
+ { once: true }
+ );
+ });
+ button.click();
+ await clickDone;
+ }
+ );
+
+ ok(true, "Fullscreen should be exited");
+ });
+ }
+});
+
+add_task(async function OpenExternalProtocolOnFullscreen() {
+ for (const useClick of [true, false]) {
+ await BrowserTestUtils.withNewTab(CONTENT, async browser => {
+ const leavelFullscreen = waitForFullscreenState(document, false, true);
+ await SpecialPowers.spawn(
+ browser,
+ [useClick],
+ async function (shouldClick) {
+ let button = content.document.querySelector("button");
+ button.addEventListener("click", function () {
+ content.document.documentElement.requestFullscreen();
+ });
+ button.click();
+
+ await new Promise(r => {
+ content.document.addEventListener("fullscreenchange", r);
+ });
+
+ if (shouldClick) {
+ content.document.querySelector("a").click();
+ } else {
+ content.document.location = "mailto:test@example.com";
+ }
+ }
+ );
+
+ await leavelFullscreen;
+ ok(true, "Fullscreen should be exited");
+ });
+ }
+});
diff --git a/dom/base/test/fullscreen/chrome.ini b/dom/base/test/fullscreen/chrome.ini
new file mode 100644
index 0000000000..cf60c0f0b5
--- /dev/null
+++ b/dom/base/test/fullscreen/chrome.ini
@@ -0,0 +1,10 @@
+[DEFAULT]
+tags = fullscreen
+
+[test_fullscreen.xhtml]
+support-files =
+ file_MozDomFullscreen.html
+[test_MozDomFullscreen_event.xhtml]
+support-files =
+ fullscreen.xhtml
+ MozDomFullscreen_chrome.xhtml
diff --git a/dom/base/test/fullscreen/dummy_page.html b/dom/base/test/fullscreen/dummy_page.html
new file mode 100644
index 0000000000..fd238954c6
--- /dev/null
+++ b/dom/base/test/fullscreen/dummy_page.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Dummy test page</title>
+<meta charset="utf-8"/>
+</head>
+<body>
+<p>Dummy test page</p>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_MozDomFullscreen.html b/dom/base/test/fullscreen/file_MozDomFullscreen.html
new file mode 100644
index 0000000000..f954892706
--- /dev/null
+++ b/dom/base/test/fullscreen/file_MozDomFullscreen.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+</head>
+<body style="background-color: blue;">
+<p>Outer doc</p>
+<iframe id="innerFrame" src="http://mochi.test:8888/"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-api-keys.html b/dom/base/test/fullscreen/file_fullscreen-api-keys.html
new file mode 100644
index 0000000000..f526aa55ba
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-api-keys.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+</head>
+<body>
+<script>
+window.addEventListener("Test:DispatchKeyEvents", aEvent => {
+ var keyCode = KeyEvent["DOM_" + aEvent.detail.code];
+
+ document.body.focus();
+ var evt = new KeyboardEvent("keydown", {
+ bubbles: true,
+ cancelable: true,
+ view: window,
+ keyCode,
+ charCode: 0,
+ });
+ document.body.dispatchEvent(evt);
+
+ evt = new KeyboardEvent("keypress", {
+ bubbles: true,
+ cancelable: true,
+ view: window,
+ keyCode,
+ charCode: 0,
+ });
+ document.body.dispatchEvent(evt);
+
+ evt = new KeyboardEvent("keyup", {
+ bubbles: true,
+ cancelable: true,
+ view: window,
+ keyCode,
+ charCode: 0,
+ });
+ document.body.dispatchEvent(evt);
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-api-race.html b/dom/base/test/fullscreen/file_fullscreen-api-race.html
new file mode 100644
index 0000000000..8310bc0a60
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-api-race.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Helper file for test_fullscreen-api-race.html</title>
+</head>
+<body onload="window.opener.postMessage('ready', '*');">
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-api.html b/dom/base/test/fullscreen/file_fullscreen-api.html
new file mode 100644
index 0000000000..645e6ece46
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-api.html
@@ -0,0 +1,340 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=545812
+
+Test DOM full-screen API.
+
+-->
+<head>
+ <title>Test for Bug 545812</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ body {
+ background-color: black;
+ }
+ </style>
+</head>
+<body>
+<div id="fullscreen-element"></div>
+<script type="application/javascript">
+
+/** Test for Bug 545812 **/
+
+function ok(condition, msg) {
+ opener.ok(condition, "[fullscreen] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[fullscreen] " + msg);
+}
+
+/*
+<html>
+ <body onload='document.body.requestFullscreen();'>
+ <iframe id='inner-frame'></iframe>
+ </body>
+</html>
+*/
+var iframeContents = "<html><body onload='parent.SimpleTest.waitForFocus(function(){document.body.requestFullscreen();});'><iframe id='inner-frame'></iframe></body></html>";
+
+var iframe = null;
+var outOfDocElement = null;
+var inDocElement = null;
+var container = null;
+var button = null;
+
+
+function sendMouseClick(element) {
+ synthesizeMouseAtCenter(element, {});
+}
+
+function assertPromiseResolved(promise, msg) {
+ let { state, value } = SpecialPowers.PromiseDebugging.getState(promise);
+ is(state, "fulfilled", "Promise should have been resolved " + msg);
+ is(value, undefined, "Promise should be resolved with undefined " + msg);
+}
+
+function assertPromiseRejected(promise, msg) {
+ let { state, reason } = SpecialPowers.PromiseDebugging.getState(promise);
+ is(state, "rejected", "Promise should have been rejected " + msg);
+ // XXX Actually we should be testing "instanceof TypeError", but it
+ // doesn't work as expected currently. See bug 1412856.
+ is(reason.name, "TypeError",
+ "Promise should be rejected with TypeError " + msg);
+}
+
+const FULLSCREEN_ELEMENT = document.getElementById("fullscreen-element");
+let promise;
+
+function enter1(event) {
+ is(event.target, FULLSCREEN_ELEMENT,
+ "Event target should be the fullscreen element #1");
+ ok(document.fullscreen, "Document should be in fullscreen");
+ is(document.fullscreenElement, FULLSCREEN_ELEMENT,
+ "Full-screen element should be div element.");
+ ok(document.fullscreenElement.matches(":fullscreen"),
+ "FSE should match :fullscreen");
+ addFullscreenChangeContinuation("exit", exit1);
+ FULLSCREEN_ELEMENT.remove();
+ is(document.fullscreenElement, null,
+ "Full-screen element should be null after removing.");
+}
+
+function exit1(event) {
+ document.body.appendChild(FULLSCREEN_ELEMENT);
+ is(document.fullscreenElement, null,
+ "Full-screen element should still be null after re-adding former FSE.");
+ is(event.target, document, "Event target should be the document #2");
+ ok(!document.fullscreen, "Document should not be in fullscreen");
+ is(document.fullscreenElement, null, "Full-screen element should be null.");
+ iframe = document.createElement("iframe");
+ iframe.allowFullscreen = true;
+ addFullscreenChangeContinuation("enter", enter2);
+ document.body.appendChild(iframe);
+ iframe.srcdoc = iframeContents;
+}
+
+function enter2(event) {
+ is(event.target, iframe,
+ "Event target should be the fullscreen iframe #3");
+ is(document.fullscreenElement, iframe,
+ "Full-screen element should be iframe element.");
+ is(iframe.contentDocument.fullscreenElement, iframe.contentDocument.body,
+ "Full-screen element in subframe should be body");
+
+ // The iframe's body is full-screen. Cancel full-screen in the subdocument to return
+ // the full-screen element to the previous full-screen element. This causes
+ // a fullscreenchange event.
+ addFullscreenChangeContinuation("exit", exit2);
+ promise = document.exitFullscreen();
+}
+
+function exit2(event) {
+ is(document.fullscreenElement, null,
+ "Full-screen element should have rolled back.");
+ is(iframe.contentDocument.fullscreenElement, null,
+ "Full-screen element in subframe should be null");
+ assertPromiseResolved(promise, "in exit2");
+
+ addFullscreenChangeContinuation("enter", enter3);
+ promise = FULLSCREEN_ELEMENT.requestFullscreen();
+}
+
+function enter3(event) {
+ is(event.target, FULLSCREEN_ELEMENT,
+ "Event target should be the fullscreen element #3");
+ is(document.fullscreenElement, FULLSCREEN_ELEMENT,
+ "Full-screen element should be div.");
+ assertPromiseResolved(promise, "in enter3");
+
+ // Transplant the FSE into subdoc. Should exit full-screen.
+ addFullscreenChangeContinuation("exit", exit3);
+ var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
+ _innerFrame.contentDocument.body.appendChild(FULLSCREEN_ELEMENT);
+ is(document.fullscreenElement, null,
+ "Full-screen element transplanted, should be null.");
+ is(iframe.contentDocument.fullscreenElement, null,
+ "Full-screen element in outer frame should be null.");
+ is(_innerFrame.contentDocument.fullscreenElement, null,
+ "Full-screen element in inner frame should be null.");
+}
+
+function exit3(event) {
+ document.body.appendChild(FULLSCREEN_ELEMENT);
+ is(event.target, document, "Event target should be the document #3");
+ is(document.fullscreenElement, null, "Full-screen element should be null.");
+ document.body.removeChild(iframe);
+ iframe = null;
+
+ // Do a request out of document. It should be denied.
+ // Continue test in the following fullscreenerror handler.
+ outOfDocElement = document.createElement("div");
+ addFullscreenErrorContinuation(error1);
+ promise = outOfDocElement.requestFullscreen();
+}
+
+function error1(event) {
+ ok(!document.fullscreenElement,
+ "Requests for full-screen from not-in-doc elements should fail.");
+ assertPromiseRejected(promise, "in error1");
+ container = document.createElement("div");
+ inDocElement = document.createElement("div");
+ container.appendChild(inDocElement);
+ FULLSCREEN_ELEMENT.appendChild(container);
+
+ addFullscreenChangeContinuation("enter", enter4);
+ inDocElement.requestFullscreen();
+}
+
+function enter4(event) {
+ is(event.target, inDocElement,
+ "Event target should be the fullscreen element #4");
+ is(document.fullscreenElement, inDocElement, "FSE should be inDocElement.");
+
+ // Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
+ addFullscreenChangeContinuation("exit", exit_to_arg_test_1);
+ container.remove();
+ is(document.fullscreenElement, null,
+ "Should not have a full-screen element again.");
+}
+
+async function exit_to_arg_test_1(event) {
+ ok(!document.fullscreenElement,
+ "Should have left full-screen mode (third time).");
+ addFullscreenChangeContinuation("enter", enter_from_arg_test_1);
+ var threw = false;
+ try {
+ await FULLSCREEN_ELEMENT.requestFullscreen(123);
+ } catch (e) {
+ threw = true;
+ // trigger normal fullscreen so that we continue
+ FULLSCREEN_ELEMENT.requestFullscreen();
+ }
+ ok(!threw, "requestFullscreen with bogus arg (123) shouldn't throw exception");
+}
+
+function enter_from_arg_test_1(event) {
+ ok(document.fullscreenElement,
+ "Should have entered full-screen after calling with bogus (ignored) argument (fourth time)");
+ addFullscreenChangeContinuation("exit", exit_to_arg_test_2);
+ document.exitFullscreen();
+}
+
+async function exit_to_arg_test_2(event) {
+ ok(!document.fullscreenElement,
+ "Should have left full-screen mode (fourth time).");
+ addFullscreenChangeContinuation("enter", enter_from_arg_test_2);
+ var threw = false;
+ try {
+ await FULLSCREEN_ELEMENT.requestFullscreen({ vrDisplay: null });
+ } catch (e) {
+ threw = true;
+ // trigger normal fullscreen so that we continue
+ FULLSCREEN_ELEMENT.requestFullscreen();
+ }
+ ok(!threw, "requestFullscreen with { vrDisplay: null } shouldn't throw exception");
+}
+
+function enter_from_arg_test_2(event) {
+ ok(document.fullscreenElement,
+ "Should have entered full-screen after calling with vrDisplay null argument (fifth time)");
+ addFullscreenChangeContinuation("exit", exit4);
+ document.exitFullscreen();
+}
+
+function exit4(event) {
+ ok(!document.fullscreenElement,
+ "Should be back in non-full-screen mode (fifth time)");
+ SpecialPowers.pushPrefEnv({"set":[["full-screen-api.allow-trusted-requests-only", true]]}, function() {
+ addFullscreenErrorContinuation(error2);
+ FULLSCREEN_ELEMENT.requestFullscreen();
+ });
+}
+
+function error2(event) {
+ ok(!document.fullscreenElement,
+ "Should still be in normal mode, because calling context isn't trusted.");
+ button = document.createElement("button");
+ button.onclick = function() {
+ FULLSCREEN_ELEMENT.requestFullscreen();
+ };
+ FULLSCREEN_ELEMENT.appendChild(button);
+ addFullscreenChangeContinuation("enter", enter5);
+ sendMouseClick(button);
+}
+
+function enter5(event) {
+ ok(document.fullscreenElement, "Moved to full-screen after mouse click");
+ addFullscreenChangeContinuation("exit", exit5);
+ document.exitFullscreen();
+}
+
+function exit5(event) {
+ ok(!document.fullscreenElement,
+ "Should have left full-screen mode (last time).");
+ SpecialPowers.pushPrefEnv({
+ "set":[["full-screen-api.allow-trusted-requests-only", false],
+ ["full-screen-api.enabled", false]]}, function() {
+ is(document.fullscreenEnabled, false, "document.fullscreenEnabled should be false if full-screen-api.enabled is false");
+ addFullscreenErrorContinuation(error3);
+ FULLSCREEN_ELEMENT.requestFullscreen();
+ });
+}
+
+function error3(event) {
+ ok(!document.fullscreenElement,
+ "Should still be in normal mode, because pref is not enabled.");
+
+ SpecialPowers.pushPrefEnv({"set":[["full-screen-api.enabled", true]]}, function() {
+ is(document.fullscreenEnabled, true, "document.fullscreenEnabled should be true if full-screen-api.enabled is true");
+ opener.nextTest();
+ });
+}
+
+function begin() {
+ testNamespaces(() => {
+ addFullscreenChangeContinuation("enter", enter1);
+ FULLSCREEN_ELEMENT.requestFullscreen();
+ });
+}
+
+function testNamespaces(followupTestFn) {
+ let tests = [
+ {allowed: false, name: "element", ns: "http://www.w3.org/XML/1998/namespace"},
+ {allowed: false, name: "element", ns: "http://www.w3.org/1999/xlink"},
+ {allowed: false, name: "element", ns: "http://www.w3.org/2000/svg"},
+ {allowed: false, name: "element", ns: "http://www.w3.org/1998/Math/MathML"},
+ {allowed: false, name: "mathml", ns: "unknown"},
+ {allowed: false, name: "svg", ns: "unknown"},
+ {allowed: true, name: "element", ns: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"},
+ {allowed: true, name: "element", ns: "http://www.w3.org/1999/xhtml"},
+ {allowed: true, name: "svg", ns: "http://www.w3.org/1999/xhtml"},
+ {allowed: true, name: "math", ns: "http://www.w3.org/1999/xhtml"},
+ {allowed: true, name: "svg", ns: "http://www.w3.org/2000/svg"},
+ {allowed: true, name: "math", ns: "http://www.w3.org/1998/Math/MathML"},
+ {allowed: true, name: "element"},
+ ];
+
+ function runNextNamespaceTest() {
+ let test = tests.shift();
+ if (!test) {
+ followupTestFn();
+ return;
+ }
+
+ let elem = test.ns ? document.createElementNS(test.ns, test.name) :
+ document.createElement(test.name);
+ document.body.appendChild(elem);
+
+ if (test.allowed) {
+ addFullscreenChangeContinuation("enter", () => {
+ ok(document.fullscreen, "Document should be in fullscreen");
+ is(document.fullscreenElement, elem,
+ `Element named '${test.name}' in this namespace should be allowed: ${test.ns}`);
+ addFullscreenChangeContinuation("exit", () => {
+ document.body.removeChild(elem);
+ runNextNamespaceTest();
+ });
+ document.exitFullscreen();
+ });
+ } else {
+ addFullscreenErrorContinuation(() => {
+ ok(!document.fullscreenElement,
+ `Element named '${test.name}' in this namespace should not be allowed: ${test.ns}`);
+ document.body.removeChild(elem);
+ runNextNamespaceTest();
+ });
+ }
+
+ SimpleTest.waitForFocus(() => elem.requestFullscreen());
+ }
+
+ runNextNamespaceTest();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-async.html b/dom/base/test/fullscreen/file_fullscreen-async.html
new file mode 100644
index 0000000000..e9b4147124
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-async.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>Test for Bug 1129227</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="file_fullscreen-utils.js"></script>
+<style>
+</style>
+<button>Async Request Fullscreen</button>
+<script>
+function ok(condition, msg) {
+ opener.ok(condition, "[async] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[async] " + msg);
+}
+
+function begin() {
+ SpecialPowers.pushPrefEnv({
+ "set":[["full-screen-api.allow-trusted-requests-only", true]]
+ }, startTest);
+}
+
+function startTest() {
+ let button = document.querySelector("button");
+ button.addEventListener("click", () => {
+ setTimeout(() => document.body.requestFullscreen(), 0);
+ });
+ addFullscreenChangeContinuation("enter", enteredFullscreen);
+ addFullscreenErrorContinuation(() => {
+ ok(false, "Failed to enter fullscreen");
+ exitedFullscreen();
+ });
+ synthesizeMouseAtCenter(button, {});
+}
+
+function enteredFullscreen() {
+ is(document.fullscreenElement, document.body, "Entered fullscreen");
+ addFullscreenChangeContinuation("exit", exitedFullscreen);
+ document.exitFullscreen();
+}
+
+function exitedFullscreen() {
+ SpecialPowers.popPrefEnv(finish);
+}
+
+function finish() {
+ opener.nextTest();
+}
+</script>
diff --git a/dom/base/test/fullscreen/file_fullscreen-backdrop.html b/dom/base/test/fullscreen/file_fullscreen-backdrop.html
new file mode 100644
index 0000000000..27be77a6d1
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-backdrop.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1064843</title>
+ <style id="style"></style>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script type="text/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ html {
+ overflow: hidden;
+ }
+ #placeholder {
+ height: 1000vh;
+ }
+ </style>
+</head>
+<body>
+<div id="fullscreen"></div>
+<div id="placeholder"></div>
+<script>
+
+const gStyle = document.getElementById("style");
+const gFullscreen = document.getElementById("fullscreen");
+
+function is(a, b, msg) {
+ opener.is(a, b, "[backdrop] " + msg);
+}
+
+function isnot(a, b, msg) {
+ opener.isnot(a, b, "[backdrop] " + msg);
+}
+
+function ok(cond, msg) {
+ opener.ok(cond, "[backdrop] " + msg);
+}
+
+function info(msg) {
+ opener.info("[backdrop] " + msg);
+}
+
+function synthesizeMouseAtWindowCenter() {
+ synthesizeMouseAtPoint(innerWidth / 2, innerHeight / 2, {});
+}
+
+const gFullscreenElementBackground = getComputedStyle(gFullscreen).background;
+
+function begin() {
+ info("The default background of window should be white");
+ assertWindowPureColor(window, "white");
+ addFullscreenChangeContinuation("enter", enterFullscreen);
+ gFullscreen.requestFullscreen();
+}
+
+function setBackdropStyle(style) {
+ gStyle.textContent = `#fullscreen::backdrop { ${style} }`;
+}
+
+function enterFullscreen() {
+ is(getComputedStyle(gFullscreen).background, gFullscreenElementBackground,
+ "Computed background of #fullscreen shouldn't be changed");
+
+ info("The default background of backdrop for fullscreen is black");
+ assertWindowPureColor(window, "black");
+
+ setBackdropStyle("background: green");
+ info("The background color of backdrop should be changed to green");
+ assertWindowPureColor(window, "green");
+
+ gFullscreen.style.background = "blue";
+ info("The blue fullscreen element should cover the backdrop");
+ assertWindowPureColor(window, "blue");
+
+ gFullscreen.style.background = "";
+ setBackdropStyle("display: none");
+ info("The white body should be shown when the backdrop is hidden");
+ assertWindowPureColor(window, "white");
+
+ setBackdropStyle("");
+ info("Content should return to black because we restore the backdrop");
+ assertWindowPureColor(window, "black");
+
+ gFullscreen.style.display = "none";
+ info("The backdrop should disappear with the fullscreen element");
+ assertWindowPureColor(window, "white");
+
+ gFullscreen.style.display = "";
+ setBackdropStyle("position: absolute");
+ info("Changing position shouldn't immediately affect the view");
+ assertWindowPureColor(window, "black");
+
+ window.scroll(0, screen.height);
+ info("Scrolled up the absolutely-positioned element");
+ assertWindowPureColor(window, "white");
+
+ addFullscreenChangeContinuation("exit", exitFullscreen);
+ document.exitFullscreen();
+}
+
+function exitFullscreen() {
+ opener.nextTest();
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html b/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html
new file mode 100644
index 0000000000..61db80c228
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<button>Launch</button>
+<script>
+let button = document.querySelector("button");
+button.addEventListener("click", function(e) {
+ let newWindow = window.open("", "", "newWindow");
+ newWindow.document.write(`<!DOCTYPE HTML>
+ <button>click me!</button>
+ <script>
+ let button = document.querySelector("button");
+ button.addEventListener("click", function(e) {
+ document.documentElement.requestFullscreen();
+ setTimeout(() => {
+ while(true) {
+ // slowdown event loop
+ };
+ }, 1);
+ location.href = "https://example.org/browser/dom/base/test/fullscreen/dummy_page.html";
+ });
+ <\/script>`);
+});
+</script>
diff --git a/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html b/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html
new file mode 100644
index 0000000000..7490f12936
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<button>click me!</button>
+<script>
+let button = document.querySelector("button");
+button.addEventListener("click", function(e) {
+ document.documentElement.requestFullscreen();
+ setTimeout(() => {
+ while(true) {
+ // slowdown event loop
+ };
+ }, 1);
+ location.href = "https://example.org/browser/dom/base/test/fullscreen/dummy_page.html";
+});
+</script>
diff --git a/dom/base/test/fullscreen/file_fullscreen-denied-inner.html b/dom/base/test/fullscreen/file_fullscreen-denied-inner.html
new file mode 100644
index 0000000000..6b5916b2e2
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-denied-inner.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+</head>
+<body onload="doRequestFullscreen()">
+<script>
+function doRequestFullscreen() {
+ function handler(evt) {
+ document.removeEventListener("fullscreenchange", handler);
+ document.removeEventListener("fullscreenerror", handler);
+ parent.is(evt.type, "fullscreenerror", "Request from " +
+ `document inside ${parent.testTargetName} should be denied`);
+ parent.continueTest();
+ }
+ parent.ok(!document.fullscreenEnabled, "Fullscreen " +
+ `should not be enabled in ${parent.testTargetName}`);
+ document.addEventListener("fullscreenchange", handler);
+ document.addEventListener("fullscreenerror", handler);
+ document.documentElement.requestFullscreen();
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-denied.html b/dom/base/test/fullscreen/file_fullscreen-denied.html
new file mode 100644
index 0000000000..db9a69e71a
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-denied.html
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=545812
+
+Test DOM fullscreen API.
+
+-->
+<head>
+ <title>Test for Bug 545812</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ body {
+ background-color: black;
+ }
+ </style>
+</head>
+<body>
+
+<script type="application/javascript">
+
+/** Test for Bug 545812 **/
+
+function ok(condition, msg) {
+ opener.ok(condition, "[denied] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[denied] " + msg);
+}
+
+const INNER_FILE = "file_fullscreen-denied-inner.html";
+function setupForInnerTest(targetName, callback) {
+ window.testTargetName = targetName;
+ window.continueTest = () => {
+ delete window.testTargetName;
+ delete window.continueTest;
+ callback();
+ };
+}
+
+function begin() {
+ document.addEventListener("fullscreenchange", () => {
+ ok(false, "Should never receive " +
+ "a fullscreenchange event in the main window.");
+ });
+ SimpleTest.executeSoon(testIFrameWithoutAllowFullscreen);
+}
+
+function testIFrameWithoutAllowFullscreen() {
+ // Create an iframe without an allowfullscreen attribute, whose
+ // contents request fullscreen. The request should be denied, and
+ // we should not receive a fullscreenchange event in this document.
+ var iframe = document.createElement("iframe");
+ iframe.src = INNER_FILE;
+ // The iframe is same-origin so when we use feature policy otherwise we'd hit
+ // the "allowed" code-path (as intended). It is a bug that this test passes
+ // without the allow attribute.
+ iframe.allow = "fullscreen 'none'";
+ setupForInnerTest("an iframe without allowfullscreen", () => {
+ document.body.removeChild(iframe);
+ SimpleTest.executeSoon(testFrameElement);
+ });
+ document.body.appendChild(iframe);
+}
+
+function testFrameElement() {
+ var frameset = document.createElement("frameset");
+ var frame = document.createElement("frame");
+ frame.src = INNER_FILE;
+ frameset.appendChild(frame);
+ setupForInnerTest("a frame element", () => {
+ document.documentElement.removeChild(frameset);
+ SimpleTest.executeSoon(testObjectElement);
+ });
+ document.documentElement.appendChild(frameset);
+}
+
+function testObjectElement() {
+ var objectElem = document.createElement("object");
+ objectElem.data = INNER_FILE;
+ setupForInnerTest("an object element", () => {
+ document.body.removeChild(objectElem);
+ // In the following tests we want to test trust context requirement
+ // of fullscreen request, so temporary re-enable this pref.
+ SpecialPowers.pushPrefEnv({
+ "set":[["full-screen-api.allow-trusted-requests-only", true]]
+ }, testNonTrustContext);
+ });
+ document.body.appendChild(objectElem);
+}
+
+function testNonTrustContext() {
+ addFullscreenErrorContinuation(() => {
+ ok(!document.fullscreenElement,
+ "Should not grant request in non-trust context.");
+ SimpleTest.executeSoon(testLongRunningEventHandler);
+ });
+ document.documentElement.requestFullscreen();
+}
+
+function testLongRunningEventHandler() {
+ let timeout = SpecialPowers.getIntPref("dom.user_activation.transient.timeout") + 1000;
+
+ function longRunningHandler() {
+ window.removeEventListener("keypress", longRunningHandler);
+ // Busy loop until transient useractivation is timed out, so our request for
+ // fullscreen should be rejected.
+ var end = (new Date()).getTime() + timeout;
+ while ((new Date()).getTime() < end) {
+ ; // Wait...
+ }
+ document.documentElement.requestFullscreen();
+ }
+ addFullscreenErrorContinuation(() => {
+ ok(!document.fullscreenElement,
+ "Should not grant request in long-running event handler.");
+ SimpleTest.executeSoon(testFullscreenMouseBtn);
+ });
+ window.addEventListener("keypress", longRunningHandler);
+ sendString("a");
+}
+
+function requestFullscreenMouseBtn(event, button) {
+ let clickEl = document.createElement("p");
+ clickEl.innerText = "Click Me";
+
+ function eventHandler(evt) {
+ document.body.requestFullscreen();
+ evt.target.removeEventListener(evt, this);
+ }
+
+ clickEl.addEventListener(event, eventHandler);
+ document.body.appendChild(clickEl);
+ synthesizeMouseAtCenter(clickEl, { button });
+}
+
+async function testFullscreenMouseBtn(event, button, next) {
+ await SpecialPowers.pushPrefEnv({
+ "set": [["full-screen-api.mouse-event-allow-left-button-only", true]]
+ });
+ let fsRequestEvents = ["mousedown", "mouseup", "pointerdown", "pointerup"];
+ let mouseButtons = [1, 2];
+
+ for (let i = 0; i < fsRequestEvents.length; i++) {
+ let evt = fsRequestEvents[i];
+ for (let j = 0; j < mouseButtons.length; j++) {
+ let mouseButton = mouseButtons[j];
+ await new Promise(resolve => {
+ addFullscreenErrorContinuation(resolve);
+ requestFullscreenMouseBtn(evt, mouseButton);
+ });
+ ok(!document.fullscreenElement, `Should not grant request on '${evt}' triggered by mouse button ${mouseButton}`);
+ }
+ }
+ // Restore the pref environment we changed before
+ // entering testNonTrustContext.
+ await SpecialPowers.popPrefEnv();
+ await SpecialPowers.popPrefEnv();
+ finish();
+}
+
+function finish() {
+ opener.nextTest();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html b/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html
new file mode 100644
index 0000000000..d7d8a90aaf
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html
@@ -0,0 +1,58 @@
+ <!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=700764
+
+Verify that an ESC key press in a subdoc of a full-screen doc causes us to
+exit DOM full-screen mode.
+
+-->
+<head>
+ <title>Test for Bug 700764</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <style>
+ body:not(:fullscreen) {
+ background-color: blue;
+ }
+ </style>
+</head>
+<body>
+
+<script type="application/javascript">
+
+/** Test for Bug 700764 **/
+
+function ok(condition, msg) {
+ parent.ok(condition, msg);
+}
+
+function is(a, b, msg) {
+ parent.is(a, b, msg);
+}
+
+var escKeyReceived = false;
+var escKeySent = false;
+
+function keyHandler(event) {
+ if (escKeyReceived == KeyboardEvent.DOM_VK_ESC) {
+ escKeyReceived = true;
+ }
+}
+
+window.addEventListener("keydown", keyHandler, true);
+window.addEventListener("keyup", keyHandler, true);
+window.addEventListener("keypress", keyHandler, true);
+
+function startTest() {
+ ok(!document.fullscreenElement, "Subdoc should not be in full-screen mode");
+ ok(parent.document.fullscreenElement, "Parent should be in full-screen mode");
+ escKeySent = true;
+ window.focus();
+ synthesizeKey("KEY_Escape");
+}
+
+</script>
+</pre>
+<p>Inner frame</p>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-esc-exit.html b/dom/base/test/fullscreen/file_fullscreen-esc-exit.html
new file mode 100644
index 0000000000..f65f930b3f
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-esc-exit.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=700764
+
+Verify that an ESC key press in a subdoc of a full-screen doc causes us to
+exit DOM full-screen mode.
+
+-->
+<head>
+ <title>Test for Bug 700764</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ body:fullscreen, div:fullscreen {
+ background-color: red;
+ }
+ </style>
+</head>
+<body>
+
+<script type="application/javascript">
+
+function ok(condition, msg) {
+ opener.ok(condition, "[esc-exit] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[esc-exit] " + msg);
+}
+
+function finish() {
+ opener.nextTest();
+}
+
+function fullscreenchange1(event) {
+ is(document.fullscreenElement, document.body, "FSE should be doc");
+ addFullscreenChangeContinuation("exit", fullscreenchange2);
+ ok(!document.getElementById("subdoc").contentWindow.escKeySent, "Should not yet have sent ESC key press.");
+ document.getElementById("subdoc").contentWindow.startTest();
+}
+
+function fullscreenchange2(event) {
+ ok(document.getElementById("subdoc").contentWindow.escKeySent, "Should have sent ESC key press.");
+ ok(!document.getElementById("subdoc").contentWindow.escKeyReceived, "ESC key press to exit should not be delivered.");
+ ok(!document.fullscreenElement, "Should have left full-screen mode on ESC key press");
+ finish();
+}
+
+function begin() {
+ addFullscreenChangeContinuation("enter", fullscreenchange1);
+ document.body.requestFullscreen();
+}
+
+</script>
+
+<!-- This subframe conducts the test. -->
+<iframe id="subdoc" src="file_fullscreen-esc-exit-inner.html"></iframe>
+
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-event-order.html b/dom/base/test/fullscreen/file_fullscreen-event-order.html
new file mode 100644
index 0000000000..72fb2c9b47
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-event-order.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="file_fullscreen-utils.js"></script>
+<iframe src="empty.html" allowfullscreen></iframe>
+<script>
+function ok(condition, msg) {
+ opener.ok(condition, "[event-order] " + msg);
+}
+function is(a, b, msg) {
+ opener.is(a, b, "[event-order] " + msg);
+}
+
+let fullscreenEvents = [];
+let iframe, iframeDoc;
+
+function begin() {
+ iframe = document.querySelector("iframe");
+ iframeDoc = iframe.contentDocument;
+ document.addEventListener("fullscreenchange", evt => {
+ fullscreenEvents.push(evt);
+ });
+ iframeDoc.addEventListener("fullscreenchange", evt => {
+ fullscreenEvents.push(evt);
+ });
+ addFullscreenChangeContinuation("enter", enterFullscreen);
+ iframeDoc.body.requestFullscreen();
+}
+
+function assertFullscreenEvents(action) {
+ is(fullscreenEvents.length, 2,
+ "Two documents should have event dispatched for " + action);
+ is(fullscreenEvents[0].target, iframe,
+ "Root document should have the event dispatched first after " + action);
+ is(fullscreenEvents[1].target, iframeDoc.body,
+ "Inner document should have the event dispatched second after " + action);
+}
+
+function enterFullscreen() {
+ assertFullscreenEvents("requestFullscreen");
+ fullscreenEvents = [];
+ addFullscreenChangeContinuation("exit", exitFullscreen);
+ document.exitFullscreen();
+}
+
+function exitFullscreen() {
+ assertFullscreenEvents("exitFullscreen");
+ opener.nextTest();
+}
+</script>
diff --git a/dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html b/dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html
new file mode 100644
index 0000000000..844684b054
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+</head>
+<body onload="doRequestFullscreen()">
+<script>
+function doRequestFullscreen() {
+ let isChrome = location.search.includes("chrome");
+
+ function handler(evt) {
+ document.removeEventListener("fullscreenchange", handler);
+ document.removeEventListener("fullscreenerror", handler);
+ const enabled = isChrome ? SpecialPowers.wrap(document).fullscreenEnabled
+ : document.fullscreenEnabled;
+ if (evt.type == "fullscreenchange") {
+ document.addEventListener("fullscreenchange", () => parent.continueTest(evt.type, enabled), {once: true});
+ document.exitFullscreen();
+ } else {
+ parent.continueTest(evt.type, enabled);
+ }
+ }
+ document.addEventListener("fullscreenchange", handler);
+ document.addEventListener("fullscreenerror", handler);
+ parent.opener.info("Requesting fullscreen");
+ if (isChrome) {
+ SpecialPowers.wrap(document.documentElement).requestFullscreen();
+ } else {
+ document.documentElement.requestFullscreen();
+ }
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-featurePolicy.html b/dom/base/test/fullscreen/file_fullscreen-featurePolicy.html
new file mode 100644
index 0000000000..c8b943c612
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-featurePolicy.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for FeaturePolicy + fullscreen</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ body {
+ background-color: black;
+ }
+ </style>
+</head>
+<body>
+
+<script type="application/javascript">
+function ok(condition, msg) {
+ opener.ok(condition, "[featurePolicy] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[featurePolicy] " + msg);
+}
+
+const INNER_FILE = "file_fullscreen-featurePolicy-inner.html";
+
+function begin() {
+ nextTest();
+}
+
+var tests = [
+ ["fullscreen 'none'", "fullscreenerror"],
+ ["fullscreen", "fullscreenchange"],
+ ["fullscreen 'src'", "fullscreenchange"],
+ ["fullscreen 'self'", "fullscreenchange"],
+ ["fullscreen *", "fullscreenchange"],
+ ["fullscreen http://random.net", "fullscreenerror"],
+ [null, "fullscreenchange"],
+];
+
+async function nextTest() {
+ if (!tests.length) {
+ opener.nextTest();
+ return;
+ }
+
+ let [value, expectedEvent] = tests.shift();
+
+ for (const isChrome of [false, true]) {
+ opener.info(`Running ${value} ${isChrome ? "w/" : "wo/"} chrome privileges`);
+
+ // Create an iframe with an allowfullscreen and with an allow attribute.
+ // The request should be denied or allowed, based on the current test.
+ const iframe = document.createElement("iframe");
+ iframe.setAttribute("allowfullscreen", "true");
+ if (value) {
+ iframe.setAttribute("allow", value);
+ }
+ iframe.src = INNER_FILE + (isChrome ? "?chrome" : "");
+
+ const setupForInnerTest = targetName => {
+ window.testTargetName = targetName;
+ return new Promise(resolve => {
+ window.continueTest = (event, enabled) => {
+ delete window.testTargetName;
+ delete window.continueTest;
+ resolve({ event, enabled });
+ };
+ document.body.appendChild(iframe);
+ });
+ };
+
+ const { event, enabled } = await setupForInnerTest(
+ `an iframe+allowfullscreen+allow:${value}+isChrome:${isChrome}`
+ );
+
+ if (isChrome) {
+ is(event, "fullscreenchange", "Expected a fullscreenchange event");
+ ok(enabled, "Should be enabled in chrome");
+ } else {
+ is(event, expectedEvent, "Expected a " + expectedEvent + " event");
+ is(enabled, expectedEvent == "fullscreenchange", "Should be appropriately enabled");
+ }
+ iframe.remove();
+ }
+ SimpleTest.executeSoon(nextTest);
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-focus-inner.html b/dom/base/test/fullscreen/file_fullscreen-focus-inner.html
new file mode 100644
index 0000000000..73d39a9d83
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-focus-inner.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Focus test - child window</title>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+
+<script type="application/javascript">
+
+function enterFullscreen() {
+ addFullscreenErrorContinuation(() => { opener.enteredFullscreen(false); });
+
+ addFullscreenChangeContinuation("enter", () => {
+ opener.enteredFullscreen(true);
+ });
+
+ document.body.requestFullscreen();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-focus.html b/dom/base/test/fullscreen/file_fullscreen-focus.html
new file mode 100644
index 0000000000..be91025f45
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-focus.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+
+Test that a fullscreen request fails if the window is not focused.
+
+Open window1, open window2, focus window2, and then attempt to fullscreen
+window1 while it is not focused. The fullscreen attempt should be rejected
+because the window is not focused.
+
+-->
+<head>
+ <title>Test fullscreen request is blocked when window is not focused</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+
+<script type="application/javascript">
+
+function ok(condition, msg) {
+ opener.ok(condition, "[focus] " + msg);
+}
+
+var window1, window2;
+
+function openWindow() {
+ var w = window.open("file_fullscreen-focus-inner.html", "",
+ "width=500,height=500");
+ return w;
+}
+
+function begin() {
+ window1 = openWindow();
+ window1.focus();
+
+ SimpleTest.waitForFocus(function(){
+ window2 = openWindow();
+ window2.focus();
+
+ SimpleTest.waitForFocus(function(){
+ // Now that window2 is focused, attempt to fullscreen window1.
+ // This should fail.
+ window1.enterFullscreen("one");
+ }, window2);
+
+ }, window1);
+}
+
+async function enteredFullscreen(enteredSuccessfully) {
+ ok(!enteredSuccessfully, "window1 did not enter fullscreen");
+
+ if (enteredSuccessfully) {
+ await window1.document.exitFullscreen()
+ }
+
+ window1.close();
+ window2.close();
+ opener.nextTest();
+}
+
+</script>
+</pre>
+<div id="full-screen-element"></div>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-hidden.html b/dom/base/test/fullscreen/file_fullscreen-hidden.html
new file mode 100644
index 0000000000..bd8c8189c9
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-hidden.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=697636
+-->
+<head>
+ <title>Test for Bug 697636</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<iframe id="f" srcdoc="<body text=green>1" allowfullscreen></iframe>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=697636">Mozilla Bug 697636</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 697636 **/
+
+var frameWin;
+var e1;
+
+function begin()
+{
+ var f = document.getElementById("f");
+ frameWin = f.contentWindow;
+ e1 = frameWin.document.documentElement;
+ f.srcdoc = "<body text=blue onload='parent.b2()'>2";
+}
+
+function b2()
+{
+ try {
+ e1.requestFullscreen();
+ } catch(e) {
+ opener.ok(false, "[hidden] Should not enter full-screen");
+ }
+ setTimeout(done, 0);
+}
+
+function done() {
+ opener.ok(!document.fullscreenElement, "[hidden] Should not have entered full-screen mode in hidden document.");
+ opener.ok(!e1.ownerDocument.fullscreenElement, "[hidden] Requesting owner should not have entered full-screen mode.");
+ opener.nextTest();
+}
+
+</script>
+</pre>
+</body>
+
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html b/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html
new file mode 100644
index 0000000000..4a614fdecf
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html
@@ -0,0 +1,5 @@
+<html onclick="div.requestFullscreen()">
+<body>
+<div name="div" id="div" style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html b/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html
new file mode 100644
index 0000000000..b60dea43bf
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html
@@ -0,0 +1,5 @@
+<div name="div" id="div" style="width: 100px; height: 100px; background: blue;">
+<iframe id="iframe" allowfullscreen="yes"
+ src="http://example.org/browser/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html">
+</iframe>
+</div><br>
diff --git a/dom/base/test/fullscreen/file_fullscreen-iframe-top.html b/dom/base/test/fullscreen/file_fullscreen-iframe-top.html
new file mode 100644
index 0000000000..dddf4930c2
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-iframe-top.html
@@ -0,0 +1,5 @@
+<div name="div" id="div" style="width: 100px; height: 100px; background: red;">
+<iframe id="iframe" allowfullscreen="yes"
+ src="http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html">
+</iframe>
+</div><br>
diff --git a/dom/base/test/fullscreen/file_fullscreen-lenient-setters.html b/dom/base/test/fullscreen/file_fullscreen-lenient-setters.html
new file mode 100644
index 0000000000..02491c177e
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-lenient-setters.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1268798</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+<script>
+"use strict";
+
+function ok(condition, msg) {
+ opener.ok(condition, "[lenient-setters] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[lenient-setters] " + msg);
+}
+
+function info(msg) {
+ opener.info("[lenient-setters] " + msg);
+}
+
+let unattachedDiv = document.createElement("div");
+
+function begin() {
+ var originalValue = document.fullscreen;
+ try {
+ document.fullscreen = !document.fullscreen;
+ is(document.fullscreen, originalValue,
+ "fullscreen should not be changed");
+ } catch (e) {
+ ok(false, "Setting fullscreen should not throw");
+ }
+
+ var originalElem = document.fullscreenElement;
+ try {
+ document.fullscreenElement = unattachedDiv;
+ document.fullscreenElement = [];
+ is(document.fullscreenElement, originalElem,
+ "fullscreenElement should not be changed");
+ } catch (e) {
+ ok(false, "Setting fullscreenElement should not throw");
+ }
+
+ var originalEnabled = document.fullscreenEnabled;
+ try {
+ document.fullscreenEnabled = !originalEnabled;
+ is(document.fullscreenEnabled, originalEnabled,
+ "fullscreenEnabled should not be changed");
+ } catch (e) {
+ ok(false, "Setting fullscreenEnabled should not throw");
+ }
+
+ opener.nextTest();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-multiple-inner.html b/dom/base/test/fullscreen/file_fullscreen-multiple-inner.html
new file mode 100644
index 0000000000..cb5ca9b28e
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-multiple-inner.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 724554</title>
+</head>
+<body>
+
+<script type="application/javascript">
+
+/** Test for Bug 545812 **/
+function begin(id) {
+ opener.addFullscreenErrorContinuation(function() {
+ opener.ok(false, "Fullscreen denied " + id);
+ }, document);
+ opener.addFullscreenChangeContinuation("enter",
+ function() {
+ opener.enteredFullscreen(id);
+ }, document);
+ document.body.requestFullscreen();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-multiple.html b/dom/base/test/fullscreen/file_fullscreen-multiple.html
new file mode 100644
index 0000000000..f9e35b5e78
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-multiple.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=724554
+
+Test that multiple windows can be fullscreen at the same time.
+
+Open one window, focus it and enter fullscreen, then open another, focus
+it and enter fullscreen, and check that both are still fullscreen.
+
+-->
+<head>
+ <title>Test for Bug 724554</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+
+<script type="application/javascript">
+
+/** Test for Bug 545812 **/
+
+function ok(condition, msg) {
+ opener.ok(condition, "[multiple] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[multiple] " + msg);
+}
+
+var window1, window2;
+
+function openWindow(id) {
+ var w = window.open("file_fullscreen-multiple-inner.html", "", "width=500,height=500");
+ waitForLoadAndPaint(w, function() {
+ SimpleTest.waitForFocus(function() {
+ info(`Window ${id} is focused, starting test...`);
+ w.begin(id);
+ }, w);
+ w.focus();
+ });
+ return w;
+}
+
+function begin() {
+ window1 = openWindow("one");
+}
+
+function enteredFullscreen(id) {
+ if (id == "one") {
+ window2 = openWindow("two");
+ } else if (id == "two") {
+ ok(window1.document.fullscreenElement &&
+ window2.document.fullscreenElement,
+ "Both windows should be fullscreen concurrently");
+ window1.close();
+ window2.close();
+ opener.nextTest();
+ }
+}
+
+</script>
+</pre>
+<div id="full-screen-element"></div>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-navigation.html b/dom/base/test/fullscreen/file_fullscreen-navigation.html
new file mode 100644
index 0000000000..9b68fedf9a
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-navigation.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=685402
+-->
+<head>
+ <title>Test for Bug 685402</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body style="background-color: gray;">
+
+<iframe id="f" srcdoc="<body text=green>1" allowfullscreen></iframe>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=685402">Mozilla Bug 685402</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 685402 **/
+
+var frameWin;
+var e1;
+var prevEnabled;
+var prevTrusted;
+
+function begin()
+{
+ var f = document.getElementById("f");
+ frameWin = f.contentWindow;
+ e1 = frameWin.document.body;
+ document.addEventListener("fullscreenchange", function() {
+ opener.ok(document.fullscreenElement, "[navigation] Request should be granted");
+ f.srcdoc = "<body text=blue onload='parent.b2()'>2";
+ }, {once: true});
+
+ e1.requestFullscreen();
+}
+
+function b2()
+{
+ opener.ok(!document.fullscreenElement, "[navigation] Should have left full-screen due to navigation.");
+ opener.nextTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-nested.html b/dom/base/test/fullscreen/file_fullscreen-nested.html
new file mode 100644
index 0000000000..1629d8386c
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-nested.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1187801</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+<iframe src="empty.html" allowfullscreen></iframe>
+<script type="text/javascript">
+
+/** Test for Bug 1187801 **/
+
+function info(msg) {
+ opener.info("[nested] " + msg);
+}
+
+function ok(condition, msg) {
+ opener.ok(condition, "[nested] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[nested] " + msg);
+}
+
+var gInnerDoc;
+var gTestSteps;
+var gTestIndex = 0;
+
+function begin() {
+ var root = document.documentElement;
+ var iframe = document.querySelector("iframe");
+ var innerDoc = gInnerDoc = iframe.contentDocument;
+ var innerRoot = innerDoc.documentElement;
+
+ // The format of each test step is:
+ // [[action, target], [fsOuter, fsInner]] where:
+ // * "action" is "enter" or "exit" means whether we want to enter or
+ // fullscreen in this step. An action of "reset" means to force
+ // our count of enters to a certain value, to match how many exits
+ // we need to do to leave fullscreen. This is used when one exit
+ // can unwind more than one enter.
+ // * "target" is where we apply this action. For "enter" action, it
+ // is the element we want to call requestFullscreen() on, and for
+ // "exit", it is the document we want to call exitFullscreen() on.
+ // * "fsOuter" and "fsInner" are the expected fullscreen elements of
+ // the outer and inner document respectively after executing the
+ // action in this step. These are only checked after "enter" or
+ // "exit" actions.
+ gTestSteps = [
+ // innerRoot
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [[ "exit", innerDoc], [ null, null]],
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [[ "exit", document], [ null, null]],
+ // root, innerRoot
+ [["enter", root], [ root, null]],
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [[ "exit", innerDoc], [ root, null]],
+ [[ "exit", document], [ null, null]],
+ [["enter", root], [ root, null]],
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [[ "exit", document], [ root, null]],
+ [[ "exit", document], [ null, null]],
+ // iframe, innerRoot
+ [["enter", iframe], [iframe, null]],
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [[ "exit", innerDoc], [iframe, null]],
+ [[ "exit", document], [ null, null]],
+ [["enter", iframe], [iframe, null]],
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [["reset", 1], [ null, null]],
+ [[ "exit", document], [ null, null]],
+ // root, iframe, innerRoot
+ [["enter", root], [ root, null]],
+ [["enter", iframe], [iframe, null]],
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [[ "exit", innerDoc], [iframe, null]],
+ [[ "exit", document], [ root, null]],
+ [[ "exit", document], [ null, null]],
+ [["enter", root], [ root, null]],
+ [["enter", iframe], [iframe, null]],
+ [["enter", innerRoot], [iframe, innerRoot]],
+ [[ "exit", document], [ root, null]],
+ [["reset", 1], [ null, null]],
+ [[ "exit", document], [ null, null]],
+ ];
+
+ nextStep();
+}
+
+function nextStep() {
+ if (gTestIndex == gTestSteps.length) {
+ opener.nextTest();
+ return;
+ }
+
+ var index = gTestIndex;
+ var [[action, target], [fsOuter, fsInner]] = gTestSteps[gTestIndex++];
+
+ function checkAndNext() {
+ is(document.fullscreenElement, fsOuter,
+ `Fullscreen element of outer doc should match after step ${index}`);
+ is(gInnerDoc.fullscreenElement, fsInner,
+ `Fullscreen element of inner doc should match after step ${index}`);
+ nextStep();
+ }
+
+ info(`Executing step ${index}: ${action} on ${target}...`);
+ if (action == "enter") {
+ // For "enter" action, the target is the element
+ var doc = target.ownerDocument;
+ addFullscreenChangeContinuation("enter", checkAndNext, doc);
+ target.requestFullscreen();
+ } else if (action == "exit") {
+ // For "exit" action, the target is the document
+ addFullscreenChangeContinuation("exit", checkAndNext, target);
+ target.exitFullscreen();
+ } else if (action == "reset") {
+ // For "reset" action, the target is the number to setFullscreenChangeEnters.
+ setFullscreenChangeEnters(target);
+ nextStep();
+ } else {
+ ok(false, `Unknown action ${action}`);
+ }
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-newtab.html b/dom/base/test/fullscreen/file_fullscreen-newtab.html
new file mode 100644
index 0000000000..0eaf5dd546
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-newtab.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<a id="link" href="about:blank" target="_blank" rel="opener"
+ onclick="document.body.requestFullscreen()">Click here</a>
diff --git a/dom/base/test/fullscreen/file_fullscreen-prefixed.html b/dom/base/test/fullscreen/file_fullscreen-prefixed.html
new file mode 100644
index 0000000000..dfe1965365
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-prefixed.html
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 743198</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+ <div id="fullscreen"></div>
+<script>
+
+function ok(condition, msg) {
+ opener.ok(condition, "[prefixed] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[prefixed] " + msg);
+}
+
+function info(msg) {
+ opener.info("[prefixed] " + msg);
+}
+
+SimpleTest.requestFlakyTimeout(
+ "need to wait for a while to confirm no unexpected event is dispatched");
+
+let div = document.getElementById("fullscreen");
+let unattachedDiv = document.createElement('div');
+
+const NO_EVENT_HANDLER = 0;
+const PREFIXED_EVENT_ONLY = 1;
+const PREFIXED_AND_UNPREFIXED_EVENT = 2;
+
+class TestCase {
+ constructor(num, handlersOnWindow, handlersOnDocument) {
+ this.number = num;
+ this.handlersType = new Map([[window, handlersOnWindow],
+ [document, handlersOnDocument]]);
+ }
+
+ static checkState(inFullscreen, msg) {
+ var emptyOrNot = inFullscreen ? "" : "not ";
+ info(`Check fullscreen state ${msg}`);
+ is(document.mozFullScreen, inFullscreen,
+ `Should ${emptyOrNot}be in fullscreen`);
+ is(document.fullscreenElement, inFullscreen ? div : null,
+ `Fullscreen element should be ${inFullscreen ? "div" : "null"}`);
+ is(document.mozFullScreenElement, document.fullscreenElement,
+ "document.mozFullScreenElement should be identical to fullscreenElement");
+ is(div.matches(":fullscreen"), inFullscreen,
+ `Fullscreen element should ${emptyOrNot}match :fullscreen pseudo class`);
+ is(div.matches(":-moz-full-screen"), inFullscreen,
+ `Fullscreen element should ${emptyOrNot}match :-moz-full-screen pseudo class`);
+ }
+
+ changeListeners(action, eventType, handler) {
+ let method = `${action}EventListener`;
+ for (let [target, type] of this.handlersType.entries()) {
+ if (type == PREFIXED_EVENT_ONLY) {
+ target[method](`moz${eventType}`, handler);
+ } else if (type == PREFIXED_AND_UNPREFIXED_EVENT) {
+ target[method](eventType, handler);
+ target[method](`moz${eventType}`, handler);
+ } else if (type != NO_EVENT_HANDLER) {
+ ok(false, `Unknown handlers type ${type}`);
+ }
+ }
+ }
+
+ doTest(actionCallback, eventType, inFullscreen, msg) {
+ return new Promise(resolve => {
+ let timeout = 0;
+ let expectEvent = new Map();
+ for (let [target] of this.handlersType) {
+ expectEvent.set(target, this.handlersType != NO_EVENT_HANDLER);
+ }
+ let handleEvent = evt => {
+ let target = evt.currentTarget;
+ let type = this.handlersType.get(target);
+ if (type == PREFIXED_EVENT_ONLY) {
+ is(evt.type, `moz${eventType}`,
+ `Should get prefixed event on ${target}`);
+ } else if (type == PREFIXED_AND_UNPREFIXED_EVENT) {
+ is(evt.type, eventType,
+ `Should only get unprefixed event on ${target}`);
+ } else {
+ ok(false, `No event should be triggered on ${target}`);
+ }
+ // Ensure we receive each event exactly once.
+ if (expectEvent.get(target)) {
+ expectEvent.set(target, false);
+ } else {
+ ok(false, `Got an unexpected ${evt.type} event on ${target}`);
+ }
+ if (!timeout) {
+ timeout = setTimeout(() => {
+ this.changeListeners("remove", eventType, handleEvent);
+ TestCase.checkState(inFullscreen,
+ `${msg} in test case ${this.number}`);
+ resolve();
+ });
+ }
+ };
+ this.changeListeners("add", eventType, handleEvent);
+ SimpleTest.waitForFocus(() => actionCallback());
+ });
+ }
+
+ test() {
+ return new Promise(resolve => {
+ Promise.resolve().then(() => {
+ return this.doTest(() => div.mozRequestFullScreen(),
+ "fullscreenchange", true, "after request");
+ }).then(() => {
+ return this.doTest(() => document.mozCancelFullScreen(),
+ "fullscreenchange", false, "after exit");
+ }).then(() => {
+ return this.doTest(() => unattachedDiv.mozRequestFullScreen(),
+ "fullscreenerror", false, "after failed request");
+ }).then(resolve);
+ });
+ }
+}
+
+let gTestcases = [
+ new TestCase(1, PREFIXED_EVENT_ONLY, NO_EVENT_HANDLER),
+ new TestCase(2, PREFIXED_AND_UNPREFIXED_EVENT, NO_EVENT_HANDLER),
+ new TestCase(3, NO_EVENT_HANDLER, PREFIXED_EVENT_ONLY),
+ new TestCase(4, PREFIXED_EVENT_ONLY, PREFIXED_EVENT_ONLY),
+ new TestCase(5, PREFIXED_AND_UNPREFIXED_EVENT, PREFIXED_EVENT_ONLY),
+ new TestCase(6, NO_EVENT_HANDLER, PREFIXED_AND_UNPREFIXED_EVENT),
+ new TestCase(7, PREFIXED_EVENT_ONLY, PREFIXED_AND_UNPREFIXED_EVENT),
+ new TestCase(8, PREFIXED_AND_UNPREFIXED_EVENT, PREFIXED_AND_UNPREFIXED_EVENT),
+ ];
+
+function begin() {
+ TestCase.checkState(false, "at the beginning");
+ runNextTestCase();
+}
+
+function runNextTestCase() {
+ let testcase = gTestcases.shift();
+ if (!testcase) {
+ opener.nextTest();
+ return;
+ }
+ testcase.test().then(runNextTestCase);
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-resize.html b/dom/base/test/fullscreen/file_fullscreen-resize.html
new file mode 100644
index 0000000000..3050ba0d5d
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-resize.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1742421
+-->
+<head>
+ <title>Test for Bug 1742421</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="file_fullscreen-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body style="background-color: gray;">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1742421">Mozilla Bug 1742421</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1742421 **/
+
+function begin()
+{
+ addFullscreenChangeContinuation("enter", () => {
+ opener.info("[resize] Entered fullscreen");
+ // Do not use addFullscreenChangeContinuation for fullscreen exit given that
+ // it expects the window will be restored to the original size.
+ document.addEventListener("fullscreenchange", () => {
+ opener.ok(!document.fullscreenElement, "[resize] Should have left full-screen due to resize");
+ opener.nextTest();
+ }, { once: true });
+ window.resizeBy(100,100);
+ });
+ document.body.requestFullscreen();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-rollback.html b/dom/base/test/fullscreen/file_fullscreen-rollback.html
new file mode 100644
index 0000000000..b1578b39cd
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-rollback.html
@@ -0,0 +1,140 @@
+ <!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=700764
+
+Verifies that cancelFullScreen() rolls back to have the previous full-screen
+element full-screen.
+
+Tests:
+* Request full-screen in doc.
+* Request full-screen in doc on element not descended from full-screen element.
+* Cancel full-screen, FSE should rollback to previous FSE.
+* Request full-screen in subdoc.
+* Cancel full-screen in subdoc, doc should be full-screen.
+* Request full-screen in subdoc.
+* Removing FSE should fully-exit full-screen.
+
+
+-->
+<head>
+ <title>Test for Bug 700764</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+
+<div id="fse">
+ <div id="fse-inner">
+ <iframe id="subdoc" allowfullscreen srcdoc="<html><body bgcolor='black'></body></html>"></iframe>
+ </div>
+</div>
+
+<div id="non-fse"></div>
+
+<script type="application/javascript">
+
+/** Test for Bug 700764 **/
+
+function ok(condition, msg) {
+ opener.ok(condition, "[rollback] " + msg);
+ if (!condition) {
+ opener.finish();
+ }
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[rollback] " + msg);
+ if (a != b) {
+ opener.finish();
+ }
+}
+
+function enterFullscreen(element, callback) {
+ addFullscreenChangeContinuation("enter", callback);
+ element.focus();
+ element.requestFullscreen();
+}
+
+function revertFullscreen(doc, callback) {
+ ok(doc.fullscreenElement != null, "Should only exit fullscreen on a fullscreen doc");
+ addFullscreenChangeContinuation("exit", callback, doc);
+ doc.exitFullscreen();
+}
+
+function e(id) {
+ return document.getElementById(id);
+}
+
+function requestFullscreen(element) {
+ element.focus();
+ element.requestFullscreen();
+}
+
+function begin() {
+ enterFullscreen(e("fse"), change1);
+}
+
+function change1() {
+ is(document.fullscreenElement, e("fse"), "Body should be FSE");
+ // Request full-screen from element not descendent from current FSE.
+ enterFullscreen(e("non-fse"), change2);
+}
+
+function change2() {
+ is(document.fullscreenElement, e("non-fse"), "FSE should be e('non-fse')");
+ revertFullscreen(document, change3);
+}
+
+function change3() {
+ is(document.fullscreenElement, e("fse"), "FSE should rollback to FSE.");
+ var iframe = e("subdoc");
+ enterFullscreen(iframe.contentDocument.body, change4);
+}
+
+function change4() {
+ var iframe = e("subdoc");
+ is(document.fullscreenElement, iframe, "Subdoc container should be FSE.");
+ is(iframe.contentDocument.fullscreenElement, iframe.contentDocument.body, "Subdoc body should be FSE in subdoc");
+ revertFullscreen(document, change5);
+}
+
+function change5() {
+ is(document.fullscreenElement, e("fse"), "FSE should rollback to FSE.");
+ revertFullscreen(document, change6);
+}
+
+function change6() {
+ is(document.fullscreenElement, null, "Should have left full-screen entirely");
+ enterFullscreen(e("fse"), change7);
+}
+
+function change7() {
+ is(document.fullscreenElement, e("fse"), "FSE should be e('fse')");
+ enterFullscreen(e("fse-inner"), change8);
+}
+
+function change8() {
+ var element = e('fse-inner');
+ is(document.fullscreenElement, element, "FSE should be e('fse-inner')");
+
+ // We're breaking out of two levels of fullscreen by removing the
+ // fullscreenElement. To make our helper functions work correctly,
+ // we set the fullscreenChangeEnters value to 1. This is a hack, but
+ // it is a hack that supports the expected behavior.
+ setFullscreenChangeEnters(1);
+ addFullscreenChangeContinuation("exit", change9);
+ info(`Removing FSE should exit fullscreen.`);
+ element.remove();
+}
+
+function change9() {
+ is(document.fullscreenElement, null, "Should have fully exited full-screen mode when removed FSE from doc");
+ opener.nextTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-scrollbar.html b/dom/base/test/fullscreen/file_fullscreen-scrollbar.html
new file mode 100644
index 0000000000..05ab51431a
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-scrollbar.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1201798</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ html, body, #measure {
+ width: 100%; height: 100%;
+ margin: 0px; border: 0px;
+ }
+ div {
+ margin: 0px; border: 0px;
+ }
+ #ref-outer { width: 100px; height: 100px; overflow: scroll; }
+ #ref-inner { width: 100%; height: 100%; }
+ </style>
+</head>
+<body>
+<div id="measure"></div>
+<div style="height: 1000vh; width: 1000vw;"></div>
+<div id="ref-outer">
+ <div id="ref-inner"></div>
+</div>
+<div id="fullscreen"></div>
+<script type="text/javascript">
+
+/** Test for Bug 1201798 */
+
+var info = msg => opener.info("[scrollbar] " + msg);
+var ok = (cond, msg) => opener.ok(cond, "[scrollbar] " + msg);
+var is = (a, b, msg) => opener.is(a, b, "[scrollbar] " + msg);
+
+var gVerticalScrollbarWidth, gHorizontalScrollbarWidth;
+var gMeasureDiv = document.getElementById("measure");
+var gFullscreenDiv = document.getElementById("fullscreen");
+
+function getMeasureRect() {
+ return gMeasureDiv.getBoundingClientRect();
+}
+
+function triggerFrameReconstruction() {
+ info("Triggering a force frame reconstruction");
+ var docElem = document.documentElement;
+ var wm = window.getComputedStyle(docElem).writingMode;
+ if (wm == "horizontal-tb") {
+ docElem.style.writingMode = "vertical-rl";
+ } else {
+ docElem.style.writingMode = "horizontal-tb";
+ }
+ docElem.getBoundingClientRect();
+}
+
+function assertHasScrollbars(elem) {
+ var rect = getMeasureRect();
+ info(`screen.width: ${screen.width}, screen.height: ${screen.height}`);
+ info(`rect.width: ${rect.width}, rect.height: ${rect.height}`);
+ ok(rect.width <= screen.width - gVerticalScrollbarWidth,
+ `Should have width less than or equal to ${screen.width - gVerticalScrollbarWidth} indicating vertical scrollbar when ${elem} is in fullscreen`);
+ ok(rect.height <= screen.height - gHorizontalScrollbarWidth,
+ `Should have height less than or equal to ${screen.height - gHorizontalScrollbarWidth} indicating horizontal scrollbar when ${elem} is in fullscreen`);
+}
+
+function assertHasNoScrollbars(elem) {
+ var rect = getMeasureRect();
+ info(`screen.width: ${screen.width}, screen.height: ${screen.height}`);
+ info(`rect.width: ${rect.width}, rect.height: ${rect.height}`);
+ is(rect.width, screen.width,
+ `Should not have vertical scrollbar when ${elem} is in fullscreen`);
+ is(rect.height, screen.height,
+ `Should not have horizontal scrollbar when ${elem} is in fullscreen`);
+}
+
+function checkScrollbars(elem, shouldHaveScrollbars) {
+ is(document.fullscreenElement, elem,
+ "Should only check the current fullscreen element");
+ var assertFunc = shouldHaveScrollbars ?
+ assertHasScrollbars : assertHasNoScrollbars;
+ assertFunc(elem);
+ triggerFrameReconstruction();
+ assertFunc(elem);
+}
+
+function begin() {
+ // Check for the use of overlay scrollbars. We can only get an accurate
+ // answer to our media query if we are Chrome-privileged. Otherwise, the
+ // media query will never match.
+ let wrappedWindow = SpecialPowers.wrap(window);
+ if (wrappedWindow.matchMedia("(-moz-overlay-scrollbars)").matches) {
+ // If overlay scrollbar is enabled, the scrollbar is not measurable,
+ // so we skip this test in that case.
+ info("Skip this test because of overlay scrollbar");
+ opener.nextTest();
+ return;
+ }
+
+ const outerElement = document.getElementById("ref-outer");
+ var rectOuter = outerElement.getBoundingClientRect();
+ var rectInner = document.getElementById("ref-inner").getBoundingClientRect();
+ info(`rectOuter: ${rectOuter.width} x ${rectOuter.height}`);
+ info(`rectInner: ${rectInner.width} x ${rectInner.height}`);
+ gVerticalScrollbarWidth = rectOuter.width - rectInner.width;
+ gHorizontalScrollbarWidth = rectOuter.height - rectInner.height;
+ ok(gVerticalScrollbarWidth != 0, "Should have vertical scrollbar");
+ ok(gHorizontalScrollbarWidth != 0, "Should have horizontal scrollbar");
+ info(`gVerticalScrollbarWidth: ${gVerticalScrollbarWidth}`);
+ info(`gHorizontalScrollbarWidth: ${gHorizontalScrollbarWidth}`);
+
+ // Remove the display of outerElement to simplify layout when window goes
+ // to fullscreen.
+ outerElement.style.display = "none";
+
+ info("Entering fullscreen on root");
+ addFullscreenChangeContinuation("enter", enteredFullscreenOnRoot);
+ document.documentElement.requestFullscreen();
+}
+
+function enteredFullscreenOnRoot() {
+ checkScrollbars(document.documentElement, true);
+ info("Entering fullscreen on div");
+ addFullscreenChangeContinuation("enter", enteredFullscreenOnDiv);
+ gFullscreenDiv.requestFullscreen();
+}
+
+function enteredFullscreenOnDiv() {
+ checkScrollbars(gFullscreenDiv, false);
+ info("Exiting fullscreen on div");
+ addFullscreenChangeContinuation("exit", exitedFullscreenOnDiv);
+ document.exitFullscreen();
+}
+
+function exitedFullscreenOnDiv() {
+ checkScrollbars(document.documentElement, true);
+ info("Exiting fullscreen on root");
+ addFullscreenChangeContinuation("exit", exitedFullscreenOnRoot);
+ document.exitFullscreen();
+}
+
+function exitedFullscreenOnRoot() {
+ opener.nextTest();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-selector.html b/dom/base/test/fullscreen/file_fullscreen-selector.html
new file mode 100644
index 0000000000..64947b6cfd
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-selector.html
@@ -0,0 +1,183 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1199522</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ div {
+ position: fixed;
+ top: 20px; height: 50px;
+ opacity: 0.3;
+ border: 5px solid black;
+ box-sizing: border-box;
+ }
+ #fullscreen0 {
+ left: 50px; width: 50px;
+ background: #ff0000;
+ border-color: #800000;
+ }
+ #fullscreen1 {
+ left: 100px; width: 50px;
+ background: #00ff00;
+ border-color: #008000;
+ }
+ #fullscreen2 {
+ left: 150px; width: 50px;
+ background: #0000ff;
+ border-color: #000080;
+ }
+ </style>
+</head>
+<body>
+<script type="application/javascript">
+
+/** Test for Bug 1199522 **/
+
+function info(msg) {
+ opener.info("[selector] " + msg);
+}
+
+function ok(condition, msg) {
+ opener.ok(condition, "[selector] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[selector] " + msg);
+}
+
+function rectEquals(rect1, rect2) {
+ return rect1.x == rect2.x && rect1.y == rect2.y &&
+ rect1.width == rect2.width && rect1.height == rect2.height;
+}
+
+function getViewportRect() {
+ return new DOMRect(0, 0, window.innerWidth, window.innerHeight);
+}
+
+var fullscreenElems = [];
+
+function checkFullscreenState(elem, hasState, viewportRect) {
+ var id = elem.id;
+ var rect = elem.getBoundingClientRect();
+ if (hasState) {
+ ok(elem.matches(":fullscreen"),
+ `${id} should match selector ":fullscreen"`);
+ ok(rectEquals(rect, viewportRect),
+ `The bounding rect of ${id} should match the viewport`);
+ } else {
+ ok(!elem.matches(":fullscreen"),
+ `${id} should not match selector ":fullscreen"`);
+ ok(rectEquals(rect, elem.initialRect),
+ `The bounding rect of ${id} should match its initial state`);
+ }
+}
+
+function checkFullscreenStates(states) {
+ var viewportRect = getViewportRect();
+ fullscreenElems.forEach((elem, index) => {
+ checkFullscreenState(elem, states[index], viewportRect);
+ });
+}
+
+function begin() {
+ fullscreenElems.push(document.getElementById('fullscreen0'));
+ fullscreenElems.push(document.getElementById('fullscreen1'));
+ fullscreenElems.push(document.getElementById('fullscreen2'));
+
+ var viewportRect = getViewportRect();
+ for (var elem of fullscreenElems) {
+ var rect = elem.getBoundingClientRect();
+ var id = elem.id;
+ elem.initialRect = rect;
+ ok(!elem.matches(":fullscreen"),
+ `${id} should not match selector ":fullscreen"`);
+ ok(!rectEquals(elem.initialRect, viewportRect),
+ `The initial bounding rect of ${id} should not match the viewport`);
+ }
+
+ info("Entering fullscreen on fullscreen0");
+ addFullscreenChangeContinuation("enter", enter0);
+ fullscreenElems[0].requestFullscreen();
+}
+
+function enter0() {
+ checkFullscreenStates([true, false, false]);
+ info("Entering fullscreen on fullscreen1");
+ addFullscreenChangeContinuation("enter", enter1);
+ fullscreenElems[1].requestFullscreen();
+}
+
+function enter1() {
+ checkFullscreenStates([true, true, false]);
+ info("Entering fullscreen on fullscreen2");
+ addFullscreenChangeContinuation("enter", enter2);
+ fullscreenElems[2].requestFullscreen();
+}
+
+function enter2() {
+ checkFullscreenStates([true, true, true]);
+ info("Leaving fullscreen on fullscreen2");
+ addFullscreenChangeContinuation("exit", exit2);
+ document.exitFullscreen();
+}
+
+function exit2() {
+ checkFullscreenStates([true, true, false]);
+ info("Leaving fullscreen on fullscreen1");
+ addFullscreenChangeContinuation("exit", exit1);
+ document.exitFullscreen();
+}
+
+function exit1() {
+ checkFullscreenStates([true, false, false]);
+ info("Leaving fullscreen on fullscreen0");
+ addFullscreenChangeContinuation("exit", exit0);
+ document.exitFullscreen();
+}
+
+function exit0() {
+ checkFullscreenStates([false, false, false]);
+
+ info("Entering fullscreen on all elements");
+ var count = 0;
+ function listener() {
+ if (++count == 3) {
+ document.removeEventListener("fullscreenchange", listener);
+ // We bypassed our fullscreenchangeenters count since we didn't
+ // do our requests with a addFullscreenChangeContinuation, so we
+ // fix up the expected value now that we're done with this part
+ // of the test.
+ setFullscreenChangeEnters(1);
+ enterAll();
+ }
+ }
+ document.addEventListener("fullscreenchange", listener);
+ fullscreenElems[0].requestFullscreen();
+ fullscreenElems[1].requestFullscreen();
+ fullscreenElems[2].requestFullscreen();
+}
+
+function enterAll() {
+ checkFullscreenStates([true, true, true]);
+ info("Fully-exiting fullscreen");
+ addFullscreenChangeContinuation("exit", exitAll);
+ synthesizeKey("KEY_Escape");
+}
+
+function exitAll() {
+ checkFullscreenStates([false, false, false]);
+ opener.nextTest();
+}
+
+</script>
+</pre>
+<div id="fullscreen0">
+ <div id="fullscreen1">
+ <div id="fullscreen2">
+ </div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-shadowdom.html b/dom/base/test/fullscreen/file_fullscreen-shadowdom.html
new file mode 100644
index 0000000000..348e08ae87
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-shadowdom.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1430305
+ Bug 1430305 - Implement ShadowRoot.fullscreenElement
+ -->
+ <head>
+ <title>Bug 1430305</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=1430305">
+ Mozilla Bug 1430305</a>
+
+ <div id="host"></div>
+
+ <pre id="test">
+ <script type="application/javascript">
+
+ function begin() {
+ var host = document.getElementById("host");
+ var shadowRoot = host.attachShadow({mode: "open"});
+ shadowRoot.innerHTML = "<div>test</div>";
+ var elem = shadowRoot.firstChild;
+ var gotFullscreenEvent = false;
+
+ document.addEventListener("fullscreenchange", function (e) {
+ if (document.fullscreenElement === host) {
+ is(shadowRoot.fullscreenElement, elem,
+ "Expected element entered fullsceen");
+ gotFullscreenEvent = true;
+ document.exitFullscreen();
+ } else {
+ opener.ok(gotFullscreenEvent, "Entered fullscreen as expected");
+ is(shadowRoot.fullscreenElement, null,
+ "Shouldn't have fullscreenElement anymore.");
+ is(document.fullscreenElement, null,
+ "Shouldn't have fullscreenElement anymore.");
+ opener.nextTest();
+ }
+ });
+ elem.requestFullscreen();
+ }
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-single.html b/dom/base/test/fullscreen/file_fullscreen-single.html
new file mode 100644
index 0000000000..2ebc58bdae
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-single.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+
+Open one window, focus it and enter fullscreen, then exit fullscreen.
+
+-->
+<head>
+ <title>Simple Fullscreen Enter and Exit Test</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+
+<div id="fullscreen-div"><p>Fullscreen div</p></div>
+
+<script type="application/javascript">
+
+function ok(condition, msg) {
+ opener.ok(condition, "[single] " + msg);
+}
+
+function is(value, expected, msg) {
+ opener.is(value, expected, "[single] " + msg);
+}
+
+function isnot(value, unexpected, msg) {
+ opener.isnot(value, unexpected, "[single] " + msg);
+}
+
+function info(msg) {
+ opener.info("[single] " + msg);
+}
+
+function windowResized() {
+ info(`Window resized to width: ${window.innerWidth}, height: ${window.innerHeight}.`);
+}
+
+async function begin() {
+ window.addEventListener('resize', windowResized);
+
+ info(`Starting window width: ${window.innerWidth}, height: ${window.innerHeight}.`);
+ let windowedWidth = window.innerWidth;
+ let windowedHeight = window.innerHeight;
+
+ info("Requesting fullscreen.");
+ let entryPromise = document.getElementById('fullscreen-div').requestFullscreen()
+ info("Fullscreen requested, waiting for promise to resolve.");
+
+ await entryPromise;
+
+ info("element.requestFullscreen() promise resolved.");
+ info(`Fullscreen window width: ${window.innerWidth}, height: ${window.innerHeight}.`);
+ isnot(document.fullscreenElement, null, "document.fullscreenElement should exist.");
+ ok(window.fullScreen, "window.fullScreen");
+ isnot(windowedWidth, window.innerWidth, "window width should be changed.");
+ isnot(windowedHeight, window.innerHeight, "window height should be changed.");
+
+ info("Requesting fullscreen exit.");
+ let exitPromise = document.exitFullscreen()
+ info("Fullscreen exit requested, waiting for promise to resolve.");
+
+ await exitPromise;
+
+ info("document.exitFullscreen() promise resolved.");
+ info(`Restored window width: ${window.innerWidth}, height: ${window.innerHeight}.`);
+ is(document.fullscreenElement, null, "document.fullscreenElement should be null.");
+ ok(!window.fullScreen, "window.fullScreen should be false.");
+ is(window.innerWidth, windowedWidth, "window width should be restored.");
+ is(window.innerHeight, windowedHeight, "window height should be restored.");
+ opener.nextTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-sub-iframe.html b/dom/base/test/fullscreen/file_fullscreen-sub-iframe.html
new file mode 100644
index 0000000000..28b0235c87
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-sub-iframe.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>Test for Bug 1609180</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="file_fullscreen-utils.js"></script>
+<style>
+</style>
+<button>Request Fullscreen on sub iframe</button>
+<iframe src="dummy_page.html" allowfullscreen></iframe>
+<script>
+function ok(condition, msg) {
+ opener.ok(condition, "[sub-iframe] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[sub-iframe] " + msg);
+}
+
+function begin() {
+ SpecialPowers.pushPrefEnv({
+ "set":[["full-screen-api.allow-trusted-requests-only", true]]
+ }, startTest);
+}
+
+let doc;
+function startTest() {
+ let button = document.querySelector("button");
+ doc = document.querySelector("iframe").contentDocument;
+ button.addEventListener("click", () => {
+ doc.documentElement.requestFullscreen();
+ });
+ addFullscreenChangeContinuation("enter", enteredFullscreen, doc);
+ addFullscreenErrorContinuation(() => {
+ ok(false, "Failed to enter fullscreen");
+ exitedFullscreen();
+ }, doc);
+ synthesizeMouseAtCenter(button, {});
+}
+
+function enteredFullscreen() {
+ is(doc.fullscreenElement, doc.documentElement, "Entered fullscreen");
+ addFullscreenChangeContinuation("exit", exitedFullscreen, doc);
+ doc.exitFullscreen();
+}
+
+function exitedFullscreen() {
+ SpecialPowers.popPrefEnv(finish);
+}
+
+function finish() {
+ opener.nextTest();
+}
+</script>
diff --git a/dom/base/test/fullscreen/file_fullscreen-svg-element.html b/dom/base/test/fullscreen/file_fullscreen-svg-element.html
new file mode 100644
index 0000000000..1dfc78aa1c
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-svg-element.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=735031
+ Bug 735031 - Fullscreen API implementation assumes an HTML Element
+ -->
+ <head>
+ <title>Bug 735031</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=73503">
+ Mozilla Bug 735031</a>
+
+ <svg id="svg-elem" width="100" height="100" viewbox="0 0 100 100">
+ <rect x="10" y="10" width="50" height="50"
+ fill="black" stroke="blue" stroke-width="2"/>
+ </svg>
+
+ <pre id="test">
+ <script type="application/javascript">
+ /*
+ * Test for Bug 735031
+ * Test locking non-html element.
+ */
+ function begin() {
+ var elem = document.getElementById("svg-elem")
+ , elemWasLocked = false;
+
+ document.addEventListener("fullscreenchange", function (e) {
+ if (document.fullscreenElement === elem) {
+ elemWasLocked = true;
+ document.exitFullscreen();
+ } else {
+ opener.ok(elemWasLocked, "Expected SVG elem to become locked.");
+ opener.nextTest();
+ }
+ });
+ elem.requestFullscreen();
+ }
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-table.html b/dom/base/test/fullscreen/file_fullscreen-table.html
new file mode 100644
index 0000000000..39c602334a
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-table.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1223561</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script type="text/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+<table style="background-color: green"></table>
+<script>
+"use strict";
+
+function ok(condition, msg) {
+ opener.ok(condition, "[table] " + msg);
+}
+
+function is(a, b, msg) {
+ opener.is(a, b, "[table] " + msg);
+}
+
+function info(msg) {
+ opener.info("[table] " + msg);
+}
+
+const gTable = document.querySelector("table");
+
+function begin() {
+ info("The default background of window should be white");
+ addFullscreenChangeContinuation("enter", enteredFullscreen);
+ assertWindowPureColor(window, "white");
+ gTable.requestFullscreen();
+}
+
+function enteredFullscreen() {
+ info("The table with green background should be in fullscreen");
+ assertWindowPureColor(window, "green");
+ gTable.style = "background: transparent";
+ info("When the table becames transparent, the black backdrop should appear");
+ assertWindowPureColor(window, "black");
+ addFullscreenChangeContinuation("exit", exitedFullscreen);
+ document.exitFullscreen();
+}
+
+function exitedFullscreen() {
+ opener.nextTest();
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-top-layer.html b/dom/base/test/fullscreen/file_fullscreen-top-layer.html
new file mode 100644
index 0000000000..9e95182b02
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-top-layer.html
@@ -0,0 +1,160 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1126230</title>
+ <style>
+ #back {
+ position: fixed !important;
+ z-index: 2147483647 !important;
+ top: 0 !important; left: 0 !important;
+ right: 0 !important; bottom: 0 !important;
+ width: 100% !important; height: 100% !important;
+ }
+ #parent {
+ position: fixed;
+ z-index: -2147483748;
+ width: 0; height: 0;
+ overflow: hidden;
+ opacity: 0;
+ mask: url(#mask);
+ clip: rect(0, 0, 0, 0);
+ clip-path: url(#clipPath);
+ filter: opacity(0%);
+ will-change: transform;
+ perspective: 10px;
+ transform: scale(0);
+ }
+ /* The following styles are copied from ua.css to ensure that
+ * no other style change may trigger frame reconstruction */
+ :root {
+ overflow: hidden !important;
+ }
+ .two #fullscreen {
+ position: fixed !important;
+ top: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+ z-index: 2147483647 !important;
+ width: 100% !important;
+ height: 100% !important;
+ margin: 0 !important;
+ min-width: 0 !important;
+ max-width: none !important;
+ min-height: 0 !important;
+ max-height: none !important;
+ box-sizing: border-box !important;
+ }
+ </style>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script type="text/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1126230">Mozilla Bug 1126230</a>
+<div id="parent">
+ <div id="fullscreen" style="background-color: green"></div>
+</div>
+<div id="back" style="background-color: red"></div>
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <clipPath id="clipPath"></clipPath>
+ <mask id="mask"></mask>
+ </defs>
+</svg>
+<script>
+const gParentProperties = [
+ "position", "zIndex", "overflow",
+ "opacity", "mask", "clip", "clipPath",
+ "filter", "willChange", "transform"
+];
+
+var gInitialVals = {};
+
+const gParent = document.getElementById("parent");
+const gFullscreen = document.getElementById("fullscreen");
+const gBack = document.getElementById("back");
+
+function is(a, b, msg) {
+ opener.is(a, b, "[top-layer] " + msg);
+}
+
+function isnot(a, b, msg) {
+ opener.isnot(a, b, "[top-layer] " + msg);
+}
+
+function ok(cond, msg) {
+ opener.ok(cond, "[top-layer] " + msg);
+}
+
+function synthesizeMouseAtWindowCenter() {
+ synthesizeMouseAtPoint(innerWidth / 2, innerHeight / 2, {});
+}
+
+
+var tests = ["one", "two"];
+
+function begin() {
+ // record initial computed style of #parent
+ const style = getComputedStyle(gParent);
+ for (var prop of gParentProperties) {
+ gInitialVals[prop] = style[prop];
+ }
+
+ nextTest();
+}
+
+function nextTest() {
+ document.body.className = tests.shift();
+ // trigger a reflow to ensure the state of frames before fullscreen
+ gFullscreen.getBoundingClientRect();
+
+ ok(!document.fullscreenElement, "Shouldn't be in fullscreen");
+ // check window snapshot
+ assertWindowPureColor(window, "red");
+ // simulate click
+ window.addEventListener("click", firstClick);
+ synthesizeMouseAtWindowCenter();
+}
+
+function firstClick(evt) {
+ window.removeEventListener("click", firstClick);
+ is(evt.target, gBack, "Click target should be #back before fullscreen");
+ addFullscreenChangeContinuation("enter", enterFullscreen);
+ gFullscreen.requestFullscreen();
+}
+
+function enterFullscreen() {
+ ok(document.fullscreenElement, "Should now be in fullscreen");
+ // check window snapshot
+ assertWindowPureColor(window, "green");
+ // check computed style of #parent
+ const style = getComputedStyle(gParent);
+ for (var prop of gParentProperties) {
+ is(style[prop], gInitialVals[prop],
+ `Computed style ${prop} of #parent should not be changed`);
+ }
+ // simulate click
+ window.addEventListener("click", secondClick);
+ synthesizeMouseAtWindowCenter();
+}
+
+function secondClick(evt) {
+ window.removeEventListener("click", secondClick);
+ is(evt.target, gFullscreen, "Click target should be #fullscreen now");
+ addFullscreenChangeContinuation("exit", exitFullscreen);
+ document.exitFullscreen();
+}
+
+function exitFullscreen() {
+ if (tests.length) {
+ nextTest();
+ } else {
+ opener.nextTest();
+ }
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen-utils.js b/dom/base/test/fullscreen/file_fullscreen-utils.js
new file mode 100644
index 0000000000..b4779da4de
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-utils.js
@@ -0,0 +1,87 @@
+// Keep track of how many fullscreenChange enters we've received, so that
+// we can balance them with the number of exits we receive. We reset this
+// to 0 when we load a test.
+var fullscreenChangeEnters = 0;
+
+addLoadEvent(function () {
+ info(`Resetting fullscreen enter count.`);
+ fullscreenChangeEnters = 0;
+});
+
+// This can be used to force a certain value for fullscreenChangeEnters
+// to handle unusual conditions -- such as exiting multiple levels of
+// fullscreen forcibly.
+function setFullscreenChangeEnters(enters) {
+ info(`Setting fullscreen enter count to ${enters}.`);
+ fullscreenChangeEnters = enters;
+}
+
+// Returns true if the window believes it is in fullscreen. This may be true even
+// before an asynchronous fullscreen transition is complete.
+function inFullscreenMode(win) {
+ return win.document.fullscreenElement;
+}
+
+// Adds a listener that will be called once a fullscreen transition
+// is complete. When type==='enter', callback is called when we've
+// received a fullscreenchange event, and the fullscreen transition is
+// complete. When type==='exit', callback is called when we've
+// received a fullscreenchange event and the window is out of
+// fullscreen. inDoc is the document which the listeners are added on,
+// if absent, the listeners are added to the current document.
+// the current document.
+function addFullscreenChangeContinuation(type, callback, inDoc) {
+ var doc = inDoc || document;
+ var topWin = doc.defaultView.top;
+ function checkCondition() {
+ if (type == "enter") {
+ fullscreenChangeEnters++;
+ return inFullscreenMode(topWin);
+ } else if (type == "exit") {
+ fullscreenChangeEnters--;
+ return fullscreenChangeEnters
+ ? inFullscreenMode(topWin)
+ : !inFullscreenMode(topWin);
+ }
+ throw new Error("'type' must be either 'enter', or 'exit'.");
+ }
+ function onFullscreenChange(event) {
+ doc.removeEventListener("fullscreenchange", onFullscreenChange);
+ ok(checkCondition(), `Should ${type} fullscreen.`);
+ // Delay invocation so other listeners have a chance to respond before
+ // we continue.
+ requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0);
+ }
+ doc.addEventListener("fullscreenchange", onFullscreenChange);
+}
+
+// Calls |callback| when the next fullscreenerror is dispatched to inDoc||document.
+function addFullscreenErrorContinuation(callback, inDoc) {
+ let doc = inDoc || document;
+ let listener = function (event) {
+ doc.removeEventListener("fullscreenerror", listener);
+ // Delay invocation so other listeners have a chance to respond before
+ // we continue.
+ requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0);
+ };
+ doc.addEventListener("fullscreenerror", listener);
+}
+
+// Waits until the window has both the load event and a MozAfterPaint called on
+// it, and then invokes the callback
+function waitForLoadAndPaint(win, callback) {
+ win.addEventListener(
+ "MozAfterPaint",
+ function () {
+ // The load event may have fired before the MozAfterPaint, in which case
+ // listening for it now will hang. Instead we check the readyState to see if
+ // it already fired, and if so, invoke the callback right away.
+ if (win.document.readyState == "complete") {
+ callback();
+ } else {
+ win.addEventListener("load", callback, { once: true });
+ }
+ },
+ { once: true }
+ );
+}
diff --git a/dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html b/dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html
new file mode 100644
index 0000000000..620bc5acf9
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1223561</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script type="text/javascript" src="file_fullscreen-utils.js"></script>
+</head>
+<body>
+<div id="target" style="width: 100px; height: 100px; background-color: green;"></div>
+<script>
+"use strict";
+
+function begin() {
+ info("Setting full zoom to 30%");
+ SpecialPowers.setFullZoom(window, 0.3);
+
+ addFullscreenChangeContinuation("enter", enteredFullscreen);
+ document.getElementById("target").requestFullscreen();
+}
+
+function enteredFullscreen() {
+ info("The element with green background should be in fullscreen");
+ assertWindowPureColor(window, "green");
+ addFullscreenChangeContinuation("exit", exitedFullscreen);
+ document.exitFullscreen();
+}
+
+function exitedFullscreen() {
+ opener.nextTest();
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/file_fullscreen_meta_viewport.html b/dom/base/test/fullscreen/file_fullscreen_meta_viewport.html
new file mode 100644
index 0000000000..9938fdda6b
--- /dev/null
+++ b/dom/base/test/fullscreen/file_fullscreen_meta_viewport.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<meta name=viewport content="width=980">
+<style>
+ #player {
+ background: green;
+ }
+ #overflow {
+ height: 500vh;
+ }
+</style>
+<div id="player"></div>
+<div id="overflow"></div>
diff --git a/dom/base/test/fullscreen/fullscreen.xhtml b/dom/base/test/fullscreen/fullscreen.xhtml
new file mode 100644
index 0000000000..2cc95642b6
--- /dev/null
+++ b/dom/base/test/fullscreen/fullscreen.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"?>
+<!--
+ Test for fullscreen sizemode in chrome
+ -->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ sizemode="fullscreen">
+
+<script>
+
+window.addEventListener("fullscreen", onFullScreen, true);
+
+function onFullScreen(event)
+{
+ window.arguments[0].done(window.fullScreen);
+}
+
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+
+<button id="find-button" label="Find"/>
+<button id="cancel-button" label="Cancel"/>
+
+</body>
+</window>
diff --git a/dom/base/test/fullscreen/fullscreen_helpers.js b/dom/base/test/fullscreen/fullscreen_helpers.js
new file mode 100644
index 0000000000..6e78015cd8
--- /dev/null
+++ b/dom/base/test/fullscreen/fullscreen_helpers.js
@@ -0,0 +1,174 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_URLS = [
+ // all frames are in different process.
+ `data:text/html,
+ <div name="div" id="div" style="width: 100px; height: 100px; background: red;">
+ <iframe id="iframe" allowfullscreen="yes"
+ src="http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html"></iframe>
+ </div>`,
+ // toplevel and inner most iframe are in same process, and middle iframe is
+ // in a different process.
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ `http://example.org/browser/dom/base/test/fullscreen/file_fullscreen-iframe-top.html`,
+ // toplevel and middle iframe are in same process, and inner most iframe is
+ // in a different process.
+ `http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-iframe-top.html`,
+];
+
+function waitRemoteFullscreenExitEvents(aBrowsingContexts) {
+ let promises = [];
+ aBrowsingContexts.forEach(([aBrowsingContext, aName]) => {
+ promises.push(
+ SpecialPowers.spawn(aBrowsingContext, [aName], async name => {
+ return new Promise(resolve => {
+ let document = content.document;
+ document.addEventListener(
+ "fullscreenchange",
+ function changeHandler() {
+ if (document.fullscreenElement) {
+ return;
+ }
+
+ ok(true, `check remote DOM fullscreen event (${name})`);
+ document.removeEventListener("fullscreenchange", changeHandler);
+ resolve();
+ }
+ );
+ });
+ })
+ );
+ });
+ return Promise.all(promises);
+}
+
+function waitDOMFullscreenEvent(
+ aDocument,
+ aIsInFullscreen,
+ aWaitUntil = false
+) {
+ return new Promise(resolve => {
+ function errorHandler() {
+ ok(false, "should not get fullscreenerror event");
+ aDocument.removeEventListener("fullscreenchange", changeHandler);
+ aDocument.removeEventListener("fullscreenerror", errorHandler);
+ resolve();
+ }
+
+ function changeHandler() {
+ if (aWaitUntil && aIsInFullscreen != !!aDocument.fullscreenElement) {
+ return;
+ }
+
+ is(
+ aIsInFullscreen,
+ !!aDocument.fullscreenElement,
+ "check DOM fullscreen (event)"
+ );
+ aDocument.removeEventListener("fullscreenchange", changeHandler);
+ aDocument.removeEventListener("fullscreenerror", errorHandler);
+ resolve();
+ }
+
+ aDocument.addEventListener("fullscreenchange", changeHandler);
+ aDocument.addEventListener("fullscreenerror", errorHandler);
+ });
+}
+
+function waitWidgetFullscreenEvent(
+ aWindow,
+ aIsInFullscreen,
+ aWaitUntil = false
+) {
+ return BrowserTestUtils.waitForEvent(aWindow, "fullscreen", false, aEvent => {
+ if (
+ aWaitUntil &&
+ aIsInFullscreen !=
+ aWindow.document.documentElement.hasAttribute("inFullscreen")
+ ) {
+ return false;
+ }
+
+ is(
+ aIsInFullscreen,
+ aWindow.document.documentElement.hasAttribute("inFullscreen"),
+ "check widget fullscreen (event)"
+ );
+ return true;
+ });
+}
+
+function waitForFullScreenObserver(
+ aDocument,
+ aIsInFullscreen,
+ aWaitUntil = false
+) {
+ return TestUtils.topicObserved("fullscreen-painted", (subject, data) => {
+ if (
+ aWaitUntil &&
+ aIsInFullscreen !=
+ aDocument.documentElement.hasAttribute("inDOMFullscreen")
+ ) {
+ return false;
+ }
+
+ is(
+ aIsInFullscreen,
+ aDocument.documentElement.hasAttribute("inDOMFullscreen"),
+ "check fullscreen (observer)"
+ );
+ return true;
+ });
+}
+
+function waitForFullscreenState(
+ aDocument,
+ aIsInFullscreen,
+ aWaitUntil = false
+) {
+ return Promise.all([
+ waitWidgetFullscreenEvent(
+ aDocument.defaultView,
+ aIsInFullscreen,
+ aWaitUntil
+ ),
+ waitDOMFullscreenEvent(aDocument, aIsInFullscreen, aWaitUntil),
+ waitForFullScreenObserver(aDocument, aIsInFullscreen, aWaitUntil),
+ ]);
+}
+
+// Wait for fullscreenchange event for fullscreen exit. And wait for
+// fullscreen-painted observed conditionally.
+async function waitForFullscreenExit(aDocument) {
+ info(`waitForFullscreenExit`);
+ let promiseFsObserver = null;
+ let observer = function () {
+ if (aDocument.documentElement.hasAttribute("inDOMFullscreen")) {
+ info(`waitForFullscreenExit, fullscreen-painted, inDOMFullscreen`);
+ Services.obs.removeObserver(observer, "fullscreen-painted");
+ promiseFsObserver = waitForFullScreenObserver(aDocument, false);
+ }
+ };
+ Services.obs.addObserver(observer, "fullscreen-painted");
+
+ await waitDOMFullscreenEvent(aDocument, false, true);
+ // If there is a fullscreen-painted observer notified for inDOMFullscreen set,
+ // we expect to have a subsequent fullscreen-painted observer notified with
+ // inDOMFullscreen unset.
+ if (promiseFsObserver) {
+ info(`waitForFullscreenExit, promiseFsObserver`);
+ await promiseFsObserver;
+ return;
+ }
+
+ Services.obs.removeObserver(observer, "fullscreen-painted");
+ // If inDOMFullscreen is set we expect to have a subsequent fullscreen-painted
+ // observer notified with inDOMFullscreen unset.
+ if (aDocument.documentElement.hasAttribute("inDOMFullscreen")) {
+ info(`waitForFullscreenExit, inDOMFullscreen`);
+ await waitForFullScreenObserver(aDocument, false, true);
+ }
+}
diff --git a/dom/base/test/fullscreen/head.js b/dom/base/test/fullscreen/head.js
new file mode 100644
index 0000000000..1e3b435d0c
--- /dev/null
+++ b/dom/base/test/fullscreen/head.js
@@ -0,0 +1,65 @@
+function pushPrefs(...aPrefs) {
+ return SpecialPowers.pushPrefEnv({ set: aPrefs });
+}
+
+function promiseWaitForEvent(
+ object,
+ eventName,
+ capturing = false,
+ chrome = false
+) {
+ return new Promise(resolve => {
+ function listener(event) {
+ info("Saw " + eventName);
+ object.removeEventListener(eventName, listener, capturing, chrome);
+ resolve(event);
+ }
+
+ info("Waiting for " + eventName);
+ object.addEventListener(eventName, listener, capturing, chrome);
+ });
+}
+
+/**
+ * Waits for the next load to complete in any browser or the given browser.
+ * If a <tabbrowser> is given it waits for a load in any of its browsers.
+ *
+ * @return promise
+ */
+function waitForDocLoadComplete(aBrowser = gBrowser) {
+ return new Promise(resolve => {
+ let listener = {
+ onStateChange(webProgress, req, flags, status) {
+ let docStop =
+ Ci.nsIWebProgressListener.STATE_IS_NETWORK |
+ Ci.nsIWebProgressListener.STATE_STOP;
+ info(
+ "Saw state " +
+ flags.toString(16) +
+ " and status " +
+ status.toString(16)
+ );
+ // When a load needs to be retargetted to a new process it is cancelled
+ // with NS_BINDING_ABORTED so ignore that case
+ if ((flags & docStop) == docStop && status != Cr.NS_BINDING_ABORTED) {
+ aBrowser.removeProgressListener(this);
+ waitForDocLoadComplete.listeners.delete(this);
+ let chan = req.QueryInterface(Ci.nsIChannel);
+ info("Browser loaded " + chan.originalURI.spec);
+ resolve();
+ }
+ },
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIWebProgressListener",
+ "nsISupportsWeakReference",
+ ]),
+ };
+ aBrowser.addProgressListener(listener);
+ waitForDocLoadComplete.listeners.add(listener);
+ info("Waiting for browser load");
+ });
+}
+// Keep a set of progress listeners for waitForDocLoadComplete() to make sure
+// they're not GC'ed before we saw the page load.
+waitForDocLoadComplete.listeners = new Set();
+registerCleanupFunction(() => waitForDocLoadComplete.listeners.clear());
diff --git a/dom/base/test/fullscreen/mochitest.ini b/dom/base/test/fullscreen/mochitest.ini
new file mode 100644
index 0000000000..ee90f8960a
--- /dev/null
+++ b/dom/base/test/fullscreen/mochitest.ini
@@ -0,0 +1,51 @@
+[DEFAULT]
+tags = fullscreen
+support-files =
+ file_fullscreen-api-race.html
+ file_fullscreen-api.html
+ file_fullscreen-async.html
+ file_fullscreen-backdrop.html
+ file_fullscreen-denied-inner.html
+ file_fullscreen-denied.html
+ file_fullscreen-esc-exit-inner.html
+ file_fullscreen-esc-exit.html
+ file_fullscreen-event-order.html
+ file_fullscreen-featurePolicy.html
+ file_fullscreen-featurePolicy-inner.html
+ file_fullscreen-focus.html
+ file_fullscreen-focus-inner.html
+ file_fullscreen-hidden.html
+ file_fullscreen-lenient-setters.html
+ file_fullscreen_meta_viewport.html
+ file_fullscreen-multiple-inner.html
+ file_fullscreen-multiple.html
+ file_fullscreen-navigation.html
+ file_fullscreen-nested.html
+ file_fullscreen-prefixed.html
+ file_fullscreen-resize.html
+ file_fullscreen-rollback.html
+ file_fullscreen-scrollbar.html
+ file_fullscreen-selector.html
+ file_fullscreen-shadowdom.html
+ file_fullscreen-single.html
+ file_fullscreen-sub-iframe.html
+ file_fullscreen-svg-element.html
+ file_fullscreen-table.html
+ file_fullscreen-top-layer.html
+ file_fullscreen-utils.js
+ file_fullscreen-with-full-zoom.html
+
+[test_fullscreen-api-race.html]
+skip-if = toolkit == 'android' # same as test_fullscreen-api.html, 1356570
+ os == "mac" && debug
+[test_fullscreen-api-rapid-cycle.html]
+[test_fullscreen-api.html]
+allow_xul_xbl = true # XUL is used in file_fullscreen-api.html
+skip-if =
+ toolkit == 'android'
+ os == 'mac' # Bug 1579623, 1776996
+ http3
+[test_fullscreen_meta_viewport.html]
+[test_fullscreen_modal.html]
+skip-if =
+ http3
diff --git a/dom/base/test/fullscreen/moz.build b/dom/base/test/fullscreen/moz.build
new file mode 100644
index 0000000000..864fdc1e74
--- /dev/null
+++ b/dom/base/test/fullscreen/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += [
+ "mochitest.ini",
+]
+
+MOCHITEST_CHROME_MANIFESTS += [
+ "chrome.ini",
+]
+
+BROWSER_CHROME_MANIFESTS += [
+ "browser.ini",
+]
diff --git a/dom/base/test/fullscreen/test_MozDomFullscreen_event.xhtml b/dom/base/test/fullscreen/test_MozDomFullscreen_event.xhtml
new file mode 100644
index 0000000000..3041d851ac
--- /dev/null
+++ b/dom/base/test/fullscreen/test_MozDomFullscreen_event.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"?>
+<!--
+ Test that "MozShowFullScreenWarning" is dispatched to chrome on restricted keypress.
+ -->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="400" height="400">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+// Ensure the full-screen api is enabled, and will be disabled on test exit.
+var gPrevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
+var gPrevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
+var newwindow;
+
+// Ensure "fullscreen" permissions are not present on the test URI.
+var uri = Services.io.newURI("http://mochi.test:8888");
+var principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
+Services.perms.removeFromPrincipal(principal, "fullscreen");
+
+SpecialPowers.pushPrefEnv({"set": [
+ ['full-screen-api.enabled', true],
+ ['full-screen-api.allow-trusted-requests-only', false],
+ ['full-screen-api.transition-duration.enter', '0 0'],
+ ['full-screen-api.transition-duration.leave', '0 0']
+]}).then(setup);
+
+function setup() {
+ newwindow = window.browsingContext.topChromeWindow.openDialog(
+ "MozDomFullscreen_chrome.xhtml", "_blank","chrome,dialog=no,resizable=yes,width=400,height=400", window);
+}
+
+function done()
+{
+ newwindow.close();
+ SimpleTest.finish();
+}
+
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+</window>
diff --git a/dom/base/test/fullscreen/test_fullscreen-api-race.html b/dom/base/test/fullscreen/test_fullscreen-api-race.html
new file mode 100644
index 0000000000..3fe4cd3500
--- /dev/null
+++ b/dom/base/test/fullscreen/test_fullscreen-api-race.html
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test for race conditions of Fullscreen API</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>
+
+function Deferred() {
+ this.promise = new Promise(resolve => {
+ this.resolve = resolve;
+ });
+}
+
+function checkIsChromeFullscreen(win, inFullscreen) {
+ return SimpleTest.promiseWaitForCondition(
+ () => win.fullScreen == inFullscreen,
+ "The window should exit fullscreen state");
+}
+
+SimpleTest.waitForExplicitFinish();
+// XXX This actually exposes a true race condition, but it could rarely
+// happen in real world, because it only happens when requestFullscreen
+// is called immediately after exiting fullscreen in certain condition,
+// and in real life, requestFullscreen can only be called inside a user
+// event handler. But we want to fix this race condition at some point,
+// via queuing all exiting request as well as entering request together
+// which we may eventually need to do for bug 1188256.
+SimpleTest.requestFlakyTimeout(
+ "Need to wait for potential fullscreen transition");
+addLoadEvent(function () {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["full-screen-api.allow-trusted-requests-only", false],
+ ]
+ }, next);
+});
+
+const OPEN_WINDOW_FUNCS = [
+ function openNewTab() {
+ return new Promise(resolve => {
+ var win = window.open("about:blank");
+ win.addEventListener("load", () => {
+ resolve(win);
+ }, { once: true });
+ });
+ },
+ function openNewWindow() {
+ return new Promise(resolve => {
+ var win = window.open("about:blank", "", "width=300,height=200");
+ win.addEventListener("load", () => {
+ resolve(win);
+ }, { once: true });
+ });
+ }
+];
+
+const ACTION_FUNCS = [
+ function navigate(win) {
+ info("About to navigate to another page");
+ var promise = new Promise(resolve => {
+ window.addEventListener("message", () => {
+ SimpleTest.waitForFocus(() => {
+ checkIsChromeFullscreen(win, false).then(() => {
+ win.close();
+ resolve();
+ });
+ }, win);
+ }, { once: true });
+ });
+ win.location = "file_fullscreen-api-race.html";
+ return promise;
+ },
+ function closeWindow(win) {
+ info("About to close the window");
+ win.close();
+ return Promise.resolve();
+ },
+ function exitFullscreen(win) {
+ info("About to cancel fullscreen");
+ var deferred = new Deferred();
+ function listener() {
+ win.removeEventListener("fullscreenchange", listener);
+ ok(!win.document.fullscreenElement, "Should exit fullscreen");
+ checkIsChromeFullscreen(win, false).then(() => {
+ win.close();
+ deferred.resolve();
+ });
+ }
+ win.addEventListener("fullscreenchange", listener);
+ win.document.exitFullscreen();
+ return deferred.promise;
+ },
+ function exitAndClose(win) {
+ info("About to cancel fullscreen and close the window");
+ win.document.exitFullscreen();
+ win.close();
+ return Promise.resolve();
+ }
+];
+
+function* testGenerator() {
+ for (var openWinFunc of OPEN_WINDOW_FUNCS) {
+ for (var actionFunc of ACTION_FUNCS) {
+ info(`Testing ${openWinFunc.name}, ${actionFunc.name}`);
+ yield { openWinFunc, actionFunc };
+ }
+ }
+}
+
+function runTest(test) {
+ var winPromise = test.openWinFunc();
+ return winPromise.then((win) => {
+ return new Promise(resolve => {
+ SimpleTest.waitForFocus(() => resolve(win), win, true);
+ });
+ }).then((win) => {
+ return new Promise((resolve, reject) => {
+ var retried = false;
+ function listener(evt) {
+ if (!retried && evt.type == "fullscreenerror") {
+ todo(false, "Failed to enter fullscreen, but try again");
+ retried = true;
+ SimpleTest.waitForFocus(() => {
+ win.document.documentElement.requestFullscreen();
+ }, win, true);
+ return;
+ }
+ win.removeEventListener("fullscreenchange", listener);
+ win.removeEventListener("fullscreenerror", listener);
+ is(evt.type, "fullscreenchange", "Should get fullscreenchange");
+ ok(win.document.fullscreenElement, "Should have entered fullscreen");
+ ok(win.fullScreen, "The window should be in fullscreen");
+ test.actionFunc(win).then(() => resolve(win));
+ }
+ if (win.fullScreen) {
+ todo(false, "Should not open in fullscreen mode");
+ win.close();
+ reject();
+ return;
+ }
+ info("About to enter fullscreen");
+ win.addEventListener("fullscreenchange", listener);
+ win.addEventListener("fullscreenerror", listener);
+ win.document.documentElement.requestFullscreen();
+ });
+ }).then((win) => {
+ ok(win.closed, "The window should have been closed");
+ });
+}
+
+var tests = testGenerator();
+
+function next() {
+ var test = tests.next().value;
+ if (test) {
+ runTest(test).catch(() => {
+ return new Promise(resolve => {
+ SimpleTest.waitForFocus(resolve);
+ }).then(() => runTest(test));
+ }).catch(() => {
+ ok(false, "Fail to run test " +
+ `${test.openWinFunc.name}, ${test.actionFunc.name}`);
+ }).then(() => {
+ setTimeout(() => SimpleTest.waitForFocus(next), 1000);
+ });
+ } else {
+ SimpleTest.finish();
+ }
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/test_fullscreen-api-rapid-cycle.html b/dom/base/test/fullscreen/test_fullscreen-api-rapid-cycle.html
new file mode 100644
index 0000000000..36e622ad4c
--- /dev/null
+++ b/dom/base/test/fullscreen/test_fullscreen-api-rapid-cycle.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test for rapid cycling of Fullscreen API requests</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>
+
+// There are two ways that web content should be able to reliably
+// request and respond to fullscreen:
+//
+// 1) Wait on the requestFullscreen() and exitFullscreen() promises.
+// 2) Respond to the "fullscreenchange" and "fullscreenerror" events
+// after calling requestFullscreen() or exitFullscreen().
+//
+// This test exercises both methods rapidly, while checking to see
+// if any expected signal is taking too long. If awaiting a promise
+// or waiting for an event takes longer than some number of seconds,
+// the test will fail instead of timing out. This is to help detect
+// vulnerabilities in the implementation which would slow down the
+// test harness waiting for the timeout.
+
+// How many enter-exit cycles we run for each method of detecting a
+// fullscreen transition.
+const CYCLE_COUNT = 3;
+
+// How long do we wait for one transition before considering it as
+// an error.
+const TOO_LONG_SECONDS = 3;
+
+SimpleTest.requestFlakyTimeout("We race against Promises to turn possible timeouts into errors.");
+
+function rejectAfterTooLong() {
+ return new Promise((resolve, reject) => {
+ const fail = () => {
+ reject(`timeout after ${TOO_LONG_SECONDS} seconds`);
+ }
+ setTimeout(fail, TOO_LONG_SECONDS * 1000);
+ });
+}
+
+add_setup(async () => {
+ await SpecialPowers.pushPrefEnv({
+ "set": [
+ // Keep the test structure simple.
+ ["full-screen-api.allow-trusted-requests-only", false],
+
+ // Make macOS fullscreen transitions asynchronous.
+ ["full-screen-api.macos-native-full-screen", true],
+
+ // Clarify that even no-duration async transitions are vulnerable.
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"],
+ ]
+ });
+});
+
+add_task(ensureOutOfFullscreen);
+
+// It is an implementation detail that promises resolve first, and
+// then events are fired on a later event loop. For this reason,
+// it's very important that we do the rapidCycleAwaitEvents task
+// first, because we don't want to have any "stray" fullscreenchange
+// events in the pipeline when we start that task. Conversely,
+// there's really no way for the rapidCycleAwaitEvents to poison
+// the environment for the next task, which waits on promises.
+add_task(rapidCycleAwaitEvents);
+
+add_task(ensureOutOfFullscreen);
+
+add_task(rapidCycleAwaitPromises);
+
+add_task(() => { ok(true, "Completed test with one expected result."); });
+
+// This is a helper function to repeatedly invoke a Promise generator
+// until the Promise resolves, delaying by one event loop on each
+// attempt.
+async function repeatUntilSuccessful(f) {
+ let successful = false;
+ do {
+ try {
+ // Delay one event loop.
+ await new Promise(r => SimpleTest.executeSoon(r));
+ await f();
+ successful = true;
+ } catch (error) {
+ info(`repeatUntilSuccessful: error ${error}.`);
+ }
+ } while(!successful);
+}
+
+async function ensureOutOfFullscreen() {
+ // Repeatedly call exitFullscreen until we get out.
+ await repeatUntilSuccessful(async () => {
+ if (document.fullscreenElement) {
+ await document.exitFullscreen();
+ }
+ if (document.fullscreenElement) {
+ throw new Error("still in fullscreen");
+ }
+ });
+}
+
+async function rapidCycleAwaitEvents() {
+ const receiveOneFullscreenchange = () => {
+ return new Promise(resolve => {
+ document.addEventListener("fullscreenchange", resolve, { once: true });
+ });
+ };
+
+ let gotError = false;
+ for (let cycle = 0; cycle < CYCLE_COUNT; cycle++) {
+ info(`Event cycle ${cycle} request fullscreen.`);
+ const enterPromise = receiveOneFullscreenchange();
+ document.documentElement.requestFullscreen();
+ await Promise.race([enterPromise, rejectAfterTooLong()]).catch(error => {
+ ok(false, `Event cycle ${cycle} requestFullscreen errored with ${error}.`);
+ gotError = true;
+ });
+ if (gotError) {
+ break;
+ }
+
+ info(`Event cycle ${cycle} exit fullscreen.`);
+ const exitPromise = receiveOneFullscreenchange();
+ document.exitFullscreen();
+ await Promise.race([exitPromise, rejectAfterTooLong()]).catch(error => {
+ ok(false, `Event cycle ${cycle} exitFullscreen errored with ${error}.`);
+ gotError = true;
+ });
+ if (gotError) {
+ break;
+ }
+ }
+}
+
+async function rapidCycleAwaitPromises() {
+ let gotError = false;
+ for (let cycle = 0; cycle < CYCLE_COUNT; cycle++) {
+ info(`Promise cycle ${cycle} request fullscreen.`);
+ const enterPromise = document.documentElement.requestFullscreen();
+ await Promise.race([enterPromise, rejectAfterTooLong()]).catch(error => {
+ ok(false, `Promise cycle ${cycle} requestFullscreen errored with ${error}.`);
+ gotError = true;
+ });
+ if (gotError) {
+ break;
+ }
+
+ info(`Promise cycle ${cycle} exit fullscreen.`);
+ const exitPromise = document.exitFullscreen();
+ await Promise.race([exitPromise, rejectAfterTooLong()]).catch(error => {
+ ok(false, `Promise cycle ${cycle} exitFullscreen errored with ${error}.`);
+ gotError = true;
+ });
+ if (gotError) {
+ break;
+ }
+ }
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/test_fullscreen-api.html b/dom/base/test/fullscreen/test_fullscreen-api.html
new file mode 100644
index 0000000000..2a59d6eeb0
--- /dev/null
+++ b/dom/base/test/fullscreen/test_fullscreen-api.html
@@ -0,0 +1,150 @@
+ <!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 545812</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="file_fullscreen-utils.js"></script>
+ <style>
+ body {
+ background-color: black;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Tests for Bug 545812 **/
+SimpleTest.requestFlakyTimeout("untriaged");
+
+// Run the tests which go full-screen in new windows, as mochitests normally
+// run in an iframe, which by default will not have the allowfullscreen
+// attribute set, so full-screen won't work.
+var gTestWindows = [
+ { test: "file_fullscreen-single.html" },
+ { test: "file_fullscreen-multiple.html",
+ prefs: [["full-screen-api.exit-on.windowRaise", false],
+ ["full-screen-api.exit-on.windowOpen", false]] },
+ { test: "file_fullscreen-rollback.html" },
+ { test: "file_fullscreen-esc-exit.html" },
+ { test: "file_fullscreen-denied.html" },
+ { test: "file_fullscreen-api.html" },
+ { test: "file_fullscreen-hidden.html" },
+ { test: "file_fullscreen-focus.html" },
+ { test: "file_fullscreen-svg-element.html" },
+ { test: "file_fullscreen-navigation.html" },
+ { test: "file_fullscreen-scrollbar.html" },
+ { test: "file_fullscreen-selector.html" },
+ { test: "file_fullscreen-shadowdom.html" },
+ { test: "file_fullscreen-top-layer.html" },
+ { test: "file_fullscreen-backdrop.html" },
+ { test: "file_fullscreen-nested.html" },
+ { test: "file_fullscreen-prefixed.html" },
+ { test: "file_fullscreen-lenient-setters.html" },
+ { test: "file_fullscreen-table.html" },
+ { test: "file_fullscreen-event-order.html" },
+ { test: "file_fullscreen-featurePolicy.html",
+ prefs: [["dom.security.featurePolicy.header.enabled", true],
+ ["dom.security.featurePolicy.webidl.enabled", true]] },
+ { test: "file_fullscreen-async.html" },
+ { test: "file_fullscreen-sub-iframe.html" },
+ { test: "file_fullscreen-with-full-zoom.html" },
+ { test: "file_fullscreen-resize.html" },
+];
+
+var testWindow = null;
+var gTestIndex = 0;
+
+function finish() {
+ SimpleTest.finish();
+}
+
+function nextTest() {
+ if (testWindow) {
+ info("Waiting for focus to return to main window");
+ window.addEventListener("focus", function() {
+ info("main window focused, starting next test");
+ SimpleTest.executeSoon(runNextTest);
+ }, {once: true});
+ info("testWindow.close()");
+ testWindow.close();
+ } else {
+ SimpleTest.executeSoon(runNextTest);
+ }
+}
+
+function waitForEvent(eventTarget, eventName, checkFn, callback) {
+ eventTarget.addEventListener(eventName, function listener(event) {
+ if (checkFn && !checkFn(event)) {
+ return;
+ }
+ eventTarget.removeEventListener(eventName, listener);
+ callback();
+ });
+}
+
+function runNextTest() {
+ if (gTestIndex < gTestWindows.length) {
+ let test = gTestWindows[gTestIndex];
+ let promise = ("prefs" in test)
+ ? SpecialPowers.pushPrefEnv({"set": test.prefs})
+ : Promise.resolve();
+ promise.then(function() {
+ info(`Run test ${test.test}`);
+ testWindow = window.open(test.test, "", "width=500,height=500,scrollbars=yes");
+ // We'll wait for the window to load, then make sure our window is refocused
+ // before starting the test, which will get kicked off on "focus".
+ // This ensures that we're essentially back on the primary "desktop" on
+ // OS X Lion before we run the test.
+ waitForLoadAndPaint(testWindow, function() {
+ SimpleTest.waitForFocus(function() {
+ info("Were focused");
+ // For the platforms that support reporting occlusion state (e.g. Mac),
+ // we should wait until the docshell has been activated again,
+ // otherwise, the fullscreen request might be denied.
+ if (testWindow.document.hidden) {
+ info("Waiting for document to unhide");
+ waitForEvent(testWindow.document, "visibilitychange", (event) => {
+ return !testWindow.document.hidden;
+ }, testWindow.begin);
+ return;
+ }
+ testWindow.begin();
+ }, testWindow);
+ });
+ });
+ gTestIndex++;
+ } else {
+ SimpleTest.finish();
+ }
+}
+
+try {
+ window.fullScreen = true;
+} catch (e) {
+}
+is(window.fullScreen, false, "Shouldn't be able to set window fullscreen from content");
+// Ensure the full-screen api is enabled, and will be disabled on test exit.
+// Disable the requirement for trusted contexts only, so the tests are easier
+// to write
+addLoadEvent(function() {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["full-screen-api.enabled", true],
+ ["full-screen-api.allow-trusted-requests-only", false],
+ ["full-screen-api.transition-duration.enter", "0 0"],
+ ["full-screen-api.transition-duration.leave", "0 0"]
+ ]}, nextTest);
+});
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/fullscreen/test_fullscreen.xhtml b/dom/base/test/fullscreen/test_fullscreen.xhtml
new file mode 100644
index 0000000000..e338bac523
--- /dev/null
+++ b/dom/base/test/fullscreen/test_fullscreen.xhtml
@@ -0,0 +1,37 @@
+<?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"?>
+<!--
+ Test for fullscreen sizemode in chrome
+ -->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ sizemode="fullscreen">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+let newwindow = window.browsingContext.topChromeWindow.openDialog("fullscreen.xhtml", "_blank","chrome,resizable=yes", window);
+
+function done()
+{
+ // because we are cancelling the fullscreen event, it
+ // takes a bit for the fullScreen property to be set
+ setTimeout(function() { this.complete(); }, 0);
+}
+
+function complete()
+{
+ ok(newwindow.fullScreen, "window.fullScreen is true.");
+ newwindow.close();
+ SimpleTest.finish();
+}
+
+</script>
+
+
+<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+</window>
diff --git a/dom/base/test/fullscreen/test_fullscreen_meta_viewport.html b/dom/base/test/fullscreen/test_fullscreen_meta_viewport.html
new file mode 100644
index 0000000000..c2cd355c6b
--- /dev/null
+++ b/dom/base/test/fullscreen/test_fullscreen_meta_viewport.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>Test for Bug 545812</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+(async function() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.meta-viewport.enabled", true]]
+ });
+
+ let win = window.open("file_fullscreen_meta_viewport.html", "", "width=500,height=500,scrollbars=yes");
+ await SimpleTest.promiseFocus(win);
+
+ is(win.innerWidth, 980, "Meta viewport should be in effect");
+
+ let element = win.document.querySelector("#player");
+ await SpecialPowers.wrap(element).requestFullscreen();
+
+ ok(win.document.fullscreen, "Window should be in fullscreen");
+ is(win.document.fullscreenElement, element, "#player should be the fullscreen element");
+ is(win.innerWidth, screen.width, "Should be fullscreen (w)");
+ is(win.innerHeight, screen.height, "Should be fullscreen (h)");
+ is(element.clientWidth, win.innerWidth, "Element should fill the viewport vertically");
+ is(element.clientHeight, win.innerHeight, "Element should fill the viewport vertically");
+
+ SpecialPowers.wrap(win.document).exitFullscreen();
+ win.close();
+ SimpleTest.finish();
+}())
+</script>
diff --git a/dom/base/test/fullscreen/test_fullscreen_modal.html b/dom/base/test/fullscreen/test_fullscreen_modal.html
new file mode 100644
index 0000000000..94b115f93e
--- /dev/null
+++ b/dom/base/test/fullscreen/test_fullscreen_modal.html
@@ -0,0 +1,68 @@
+<!doctype html>
+<title>Test for bug 1771150</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<style>
+ #fullscreen {
+ background-color: rgba(0, 255, 0, .5);
+ }
+ #fullscreen::backdrop {
+ background-color: transparent;
+ }
+ #fullscreen, #fullscreen::backdrop {
+ pointer-events: none;
+ }
+</style>
+<div id="fullscreen"></div>
+<button>Go fullscreen</button>
+<script>
+const button = document.querySelector("button");
+let clickCount = 0;
+let lastFullscreenPromise = null;
+let shouldEnterFullscreen = false;
+button.addEventListener("click", function(e) {
+ clickCount++;
+ if (shouldEnterFullscreen) {
+ lastFullscreenPromise = document.getElementById("fullscreen").requestFullscreen();
+ }
+});
+
+function clickButton(expectEvent) {
+ let lastClickCount = clickCount;
+ synthesizeMouseAtCenter(button, {});
+ (expectEvent ? isnot : is)(lastClickCount, clickCount, `Should've ${expectEvent ? "" : "not "}been able to click`);
+}
+
+function enterFullscreen() {
+ lastFullscreenPromise = null;
+ shouldEnterFullscreen = true;
+ clickButton(true);
+ shouldEnterFullscreen = false;
+ isnot(lastFullscreenPromise, null, "Should be transitioning to fullscreen");
+ return lastFullscreenPromise;
+}
+
+async function testFullscreenIsModal(modal) {
+ info("testing modal: " + modal);
+ is(document.fullscreenElement, null, "Shouldn't be in fullscreen");
+ await SpecialPowers.pushPrefEnv({ set: [["dom.fullscreen.modal", modal]] });
+ await enterFullscreen();
+
+ clickButton(/* expectEvent = */ !modal);
+
+ ok(document.fullscreenElement.matches(":fullscreen"), "Fullscreen element matches :fullscreen");
+ is(document.fullscreenElement.matches(":modal"), modal, "Fullscreen element matches :modal");
+
+ await document.exitFullscreen();
+ clickButton(/* expectEvent = */ true);
+}
+
+add_task(async function() {
+ await testFullscreenIsModal(true);
+});
+
+add_task(async function() {
+ await testFullscreenIsModal(false);
+});
+</script>
diff --git a/dom/base/test/green.png b/dom/base/test/green.png
new file mode 100644
index 0000000000..7df25f33bd
--- /dev/null
+++ b/dom/base/test/green.png
Binary files differ
diff --git a/dom/base/test/gtest/TestContentUtils.cpp b/dom/base/test/gtest/TestContentUtils.cpp
new file mode 100644
index 0000000000..d38cb1bdca
--- /dev/null
+++ b/dom/base/test/gtest/TestContentUtils.cpp
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "jsapi.h"
+#include "js/PropertyAndElement.h" // JS_DefineProperty
+#include "nsContentUtils.h"
+#include "nsNetUtil.h"
+#include "mozilla/CycleCollectedJSContext.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/SimpleGlobalObject.h"
+
+using namespace mozilla::dom;
+
+struct IsURIInListMatch {
+ nsLiteralCString pattern;
+ bool firstMatch, secondMatch;
+};
+
+TEST(DOM_Base_ContentUtils, IsURIInList)
+{
+ nsCOMPtr<nsIURI> uri, subURI;
+ nsresult rv = NS_NewURI(getter_AddRefs(uri),
+ "https://example.com/path/favicon.ico#"_ns);
+ ASSERT_TRUE(rv == NS_OK);
+
+ rv = NS_NewURI(getter_AddRefs(subURI),
+ "http://sub.example.com/favicon.ico?"_ns);
+ ASSERT_TRUE(rv == NS_OK);
+
+ static constexpr IsURIInListMatch patterns[] = {
+ {"bar.com,*.example.com,example.com,foo.com"_ns, true, true},
+ {"bar.com,example.com,*.example.com,foo.com"_ns, true, true},
+ {"*.example.com,example.com,foo.com"_ns, true, true},
+ {"example.com,*.example.com,foo.com"_ns, true, true},
+ {"*.example.com,example.com"_ns, true, true},
+ {"example.com,*.example.com"_ns, true, true},
+ {"*.example.com/,example.com/"_ns, true, true},
+ {"example.com/,*.example.com/"_ns, true, true},
+ {"*.example.com/pa,example.com/pa"_ns, false, false},
+ {"example.com/pa,*.example.com/pa"_ns, false, false},
+ {"*.example.com/pa/,example.com/pa/"_ns, false, false},
+ {"example.com/pa/,*.example.com/pa/"_ns, false, false},
+ {"*.example.com/path,example.com/path"_ns, false, false},
+ {"example.com/path,*.example.com/path"_ns, false, false},
+ {"*.example.com/path/,example.com/path/"_ns, true, false},
+ {"example.com/path/,*.example.com/path/"_ns, true, false},
+ {"*.example.com/favicon.ico"_ns, false, true},
+ {"example.com/path/favicon.ico"_ns, true, false},
+ {"*.example.com"_ns, false, true},
+ {"example.com"_ns, true, false},
+ {"foo.com"_ns, false, false},
+ {"*.foo.com"_ns, false, false},
+ };
+
+ for (auto& entry : patterns) {
+ bool result = nsContentUtils::IsURIInList(uri, entry.pattern);
+ ASSERT_EQ(result, entry.firstMatch) << "Matching " << entry.pattern;
+
+ result = nsContentUtils::IsURIInList(subURI, entry.pattern);
+ ASSERT_EQ(result, entry.secondMatch) << "Matching " << entry.pattern;
+ }
+}
+
+TEST(DOM_Base_ContentUtils,
+ StringifyJSON_EmptyValue_UndefinedIsNullStringLiteral)
+{
+ JS::Rooted<JSObject*> globalObject(
+ mozilla::dom::RootingCx(),
+ mozilla::dom::SimpleGlobalObject::Create(
+ mozilla::dom::SimpleGlobalObject::GlobalType::BindingDetail));
+ mozilla::dom::AutoJSAPI jsAPI;
+ ASSERT_TRUE(jsAPI.Init(globalObject));
+ JSContext* cx = jsAPI.cx();
+ nsAutoString serializedValue;
+
+ ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, JS::UndefinedHandleValue,
+ serializedValue,
+ UndefinedIsNullStringLiteral));
+ ASSERT_TRUE(serializedValue.EqualsLiteral("null"));
+}
+
+TEST(DOM_Base_ContentUtils, StringifyJSON_Object_UndefinedIsNullStringLiteral)
+{
+ JS::Rooted<JSObject*> globalObject(
+ mozilla::dom::RootingCx(),
+ mozilla::dom::SimpleGlobalObject::Create(
+ mozilla::dom::SimpleGlobalObject::GlobalType::BindingDetail));
+ mozilla::dom::AutoJSAPI jsAPI;
+ ASSERT_TRUE(jsAPI.Init(globalObject));
+ JSContext* cx = jsAPI.cx();
+ nsAutoString serializedValue;
+
+ JS::Rooted<JSObject*> jsObj(cx, JS_NewPlainObject(cx));
+ JS::Rooted<JSString*> valueStr(cx, JS_NewStringCopyZ(cx, "Hello World!"));
+ ASSERT_TRUE(JS_DefineProperty(cx, jsObj, "key1", valueStr, JSPROP_ENUMERATE));
+ JS::Rooted<JS::Value> jsValue(cx, JS::ObjectValue(*jsObj));
+
+ ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, jsValue, serializedValue,
+ UndefinedIsNullStringLiteral));
+
+ ASSERT_TRUE(serializedValue.EqualsLiteral("{\"key1\":\"Hello World!\"}"));
+}
+
+TEST(DOM_Base_ContentUtils, StringifyJSON_EmptyValue_UndefinedIsVoidString)
+{
+ JS::Rooted<JSObject*> globalObject(
+ mozilla::dom::RootingCx(),
+ mozilla::dom::SimpleGlobalObject::Create(
+ mozilla::dom::SimpleGlobalObject::GlobalType::BindingDetail));
+ mozilla::dom::AutoJSAPI jsAPI;
+ ASSERT_TRUE(jsAPI.Init(globalObject));
+ JSContext* cx = jsAPI.cx();
+ nsAutoString serializedValue;
+
+ ASSERT_TRUE(nsContentUtils::StringifyJSON(
+ cx, JS::UndefinedHandleValue, serializedValue, UndefinedIsVoidString));
+
+ ASSERT_TRUE(serializedValue.IsVoid());
+}
+
+TEST(DOM_Base_ContentUtils, StringifyJSON_Object_UndefinedIsVoidString)
+{
+ JS::Rooted<JSObject*> globalObject(
+ mozilla::dom::RootingCx(),
+ mozilla::dom::SimpleGlobalObject::Create(
+ mozilla::dom::SimpleGlobalObject::GlobalType::BindingDetail));
+ mozilla::dom::AutoJSAPI jsAPI;
+ ASSERT_TRUE(jsAPI.Init(globalObject));
+ JSContext* cx = jsAPI.cx();
+ nsAutoString serializedValue;
+
+ JS::Rooted<JSObject*> jsObj(cx, JS_NewPlainObject(cx));
+ JS::Rooted<JSString*> valueStr(cx, JS_NewStringCopyZ(cx, "Hello World!"));
+ ASSERT_TRUE(JS_DefineProperty(cx, jsObj, "key1", valueStr, JSPROP_ENUMERATE));
+ JS::Rooted<JS::Value> jsValue(cx, JS::ObjectValue(*jsObj));
+
+ ASSERT_TRUE(nsContentUtils::StringifyJSON(cx, jsValue, serializedValue,
+ UndefinedIsVoidString));
+
+ ASSERT_TRUE(serializedValue.EqualsLiteral("{\"key1\":\"Hello World!\"}"));
+}
diff --git a/dom/base/test/gtest/TestMimeType.cpp b/dom/base/test/gtest/TestMimeType.cpp
new file mode 100644
index 0000000000..64a2b8f4bd
--- /dev/null
+++ b/dom/base/test/gtest/TestMimeType.cpp
@@ -0,0 +1,816 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "MimeType.h"
+#include "nsString.h"
+
+using mozilla::UniquePtr;
+
+TEST(MimeType, EmptyString)
+{
+ const auto in = u""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Empty string";
+}
+
+TEST(MimeType, JustWhitespace)
+{
+ const auto in = u" \t\r\n "_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Just whitespace";
+}
+
+TEST(MimeType, JustBackslash)
+{
+ const auto in = u"\\"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Just backslash";
+}
+
+TEST(MimeType, JustForwardslash)
+{
+ const auto in = u"/"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Just forward slash";
+}
+
+TEST(MimeType, MissingType1)
+{
+ const auto in = u"/bogus"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Missing type #1";
+}
+
+TEST(MimeType, MissingType2)
+{
+ const auto in = u" \r\n\t/bogus"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Missing type #2";
+}
+
+TEST(MimeType, MissingSubtype1)
+{
+ const auto in = u"bogus"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Missing subtype #1";
+}
+
+TEST(MimeType, MissingSubType2)
+{
+ const auto in = u"bogus/"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Missing subtype #2";
+}
+
+TEST(MimeType, MissingSubType3)
+{
+ const auto in = u"bogus;"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Missing subtype #3";
+}
+
+TEST(MimeType, MissingSubType4)
+{
+ const auto in = u"bogus; \r\n\t"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Missing subtype #3";
+}
+
+TEST(MimeType, ExtraForwardSlash)
+{
+ const auto in = u"bogus/bogus/;"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Extra forward slash";
+}
+
+TEST(MimeType, WhitespaceInType)
+{
+ const auto in = u"t\re\nx\tt /html"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Type with whitespace";
+}
+
+TEST(MimeType, WhitespaceInSubtype)
+{
+ const auto in = u"text/ h\rt\nm\tl"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Subtype with whitespace";
+}
+
+TEST(MimeType, NonAlphanumericMediaType1)
+{
+ const auto in = u"</>"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-alphanumeric media type #1";
+}
+
+TEST(MimeType, NonAlphanumericMediaType2)
+{
+ const auto in = u"(/)"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-alphanumeric media type #2";
+}
+
+TEST(MimeType, NonAlphanumericMediaType3)
+{
+ const auto in = u"{/}"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-alphanumeric media type #3";
+}
+
+TEST(MimeType, NonAlphanumericMediaType4)
+{
+ const auto in = u"\"/\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-alphanumeric media type #4";
+}
+
+TEST(MimeType, NonAlphanumericMediaType5)
+{
+ const auto in = u"\0/\0"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-alphanumeric media type #5";
+}
+
+TEST(MimeType, NonAlphanumericMediaType6)
+{
+ const auto in = u"text/html(;doesnot=matter"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-alphanumeric media type #6";
+}
+
+TEST(MimeType, NonLatin1MediaType1)
+{
+ const auto in = u"ÿ/ÿ"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-latin1 media type #1";
+}
+
+TEST(MimeType, NonLatin1MediaType2)
+{
+ const auto in = u"\x0100/\x0100"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_FALSE(parsed)
+ << "Non-latin1 media type #2";
+}
+
+TEST(MimeType, MultipleParameters)
+{
+ const auto in = u"text/html;charset=gbk;no=1;charset_=gbk_;yes=2"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals(u"text/html;charset=gbk;no=1;charset_=gbk_;yes=2"_ns))
+ << "Multiple parameters";
+}
+
+TEST(MimeType, DuplicateParameter1)
+{
+ const auto in = u"text/html;charset=gbk;charset=windows-1255"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals(u"text/html;charset=gbk"_ns))
+ << "Duplicate parameter #1";
+}
+
+TEST(MimeType, DuplicateParameter2)
+{
+ const auto in = u"text/html;charset=();charset=GBK"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals(u"text/html;charset=\"()\""_ns))
+ << "Duplicate parameter #2";
+}
+
+TEST(MimeType, CString)
+{
+ const auto in = "text/html;charset=();charset=GBK"_ns;
+ UniquePtr<CMimeType> parsed = CMimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsCString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals("text/html;charset=\"()\""_ns))
+ << "Duplicate parameter #2";
+}
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4819)
+#endif
+TEST(MimeType, NonAlphanumericParametersAreQuoted)
+{
+ const auto in = u"text/html;test=\x00FF\\;charset=gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals(u"text/html;test=\"\x00FF\\\\\";charset=gbk"_ns))
+ << "Non-alphanumeric parameters are quoted";
+}
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace1)
+{
+ const auto in = u"text/html;charset= g\\\"bk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" g\\\\\\\"bk\""))
+ << "Parameter is quoted if has leading whitespace #1";
+}
+
+TEST(MimeType, ParameterQuotedIfHasLeadingWhitespace2)
+{
+ const auto in = u"text/html;charset= \"g\\bk\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" \\\"g\\\\bk\\\"\""))
+ << "Parameter is quoted if has leading whitespace #2";
+}
+
+TEST(MimeType, ParameterQuotedIfHasInternalWhitespace)
+{
+ const auto in = u"text/html;charset=g \\b\"k"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"g \\\\b\\\"k\""))
+ << "Parameter is quoted if has internal whitespace";
+}
+
+TEST(MimeType, ImproperlyQuotedParameter1)
+{
+ const auto in = u"x/x;test=\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("x/x;test=\"\""))
+ << "Improperly-quoted parameter is handled properly #1";
+}
+
+TEST(MimeType, ImproperlyQuotedParameter2)
+{
+ const auto in = u"x/x;test=\"\\"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("x/x;test=\"\\\\\""))
+ << "Improperly-quoted parameter is handled properly #2";
+}
+
+TEST(MimeType, NonLatin1ParameterIgnored)
+{
+ const auto in = u"x/x;test=\xFFFD;x=x"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("x/x;x=x"))
+ << "Non latin-1 parameters are ignored";
+}
+
+TEST(MimeType, ParameterIgnoredIfWhitespaceInName1)
+{
+ const auto in = u"text/html;charset =gbk;charset=123"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=123"))
+ << "Parameter ignored if whitespace in name #1";
+}
+
+TEST(MimeType, ParameterIgnoredIfWhitespaceInName2)
+{
+ const auto in = u"text/html;cha rset =gbk;charset=123"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=123"))
+ << "Parameter ignored if whitespace in name #2";
+}
+
+TEST(MimeType, WhitespaceTrimmed)
+{
+ const auto in = u"\n\r\t text/plain\n\r\t ;\n\r\t charset=123\n\r\t "_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/plain;charset=123"))
+ << "Whitespace appropriately ignored";
+}
+
+TEST(MimeType, WhitespaceOnlyParameterIgnored)
+{
+ const auto in = u"x/x;x= \r\n\t"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("x/x"))
+ << "Whitespace-only parameter is ignored";
+}
+
+TEST(MimeType, IncompleteParameterIgnored1)
+{
+ const auto in = u"x/x;test"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("x/x"))
+ << "Incomplete parameter is ignored #1";
+}
+
+TEST(MimeType, IncompleteParameterIgnored2)
+{
+ const auto in = u"x/x;test="_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("x/x"))
+ << "Incomplete parameter is ignored #2";
+}
+
+TEST(MimeType, IncompleteParameterIgnored3)
+{
+ const auto in = u"x/x;test= \r\n\t"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("x/x"))
+ << "Incomplete parameter is ignored #3";
+}
+
+TEST(MimeType, IncompleteParameterIgnored4)
+{
+ const auto in = u"text/html;test;charset=gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Incomplete parameter is ignored #4";
+}
+
+TEST(MimeType, IncompleteParameterIgnored5)
+{
+ const auto in = u"text/html;test=;charset=gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Incomplete parameter is ignored #5";
+}
+
+TEST(MimeType, EmptyParameterIgnored1)
+{
+ const auto in = u"text/html ; ; charset=gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Empty parameter ignored #1";
+}
+
+TEST(MimeType, EmptyParameterIgnored2)
+{
+ const auto in = u"text/html;;;;charset=gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Empty parameter ignored #2";
+}
+
+TEST(MimeType, InvalidParameterIgnored1)
+{
+ const auto in = u"text/html;';charset=gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Invalid parameter ignored #1";
+}
+
+TEST(MimeType, InvalidParameterIgnored2)
+{
+ const auto in = u"text/html;\";charset=gbk;=123; =321"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Invalid parameter ignored #2";
+}
+
+TEST(MimeType, InvalidParameterIgnored3)
+{
+ const auto in = u"text/html;charset= \"\u007F;charset=GBK"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=GBK"))
+ << "Invalid parameter ignored #3";
+}
+
+TEST(MimeType, InvalidParameterIgnored4)
+{
+ const auto in = nsLiteralString(
+ u"text/html;charset=\"\u007F;charset=foo\";charset=GBK;charset=");
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=GBK"))
+ << "Invalid parameter ignored #4";
+}
+
+TEST(MimeType, SingleQuotes1)
+{
+ const auto in = u"text/html;charset='gbk'"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset='gbk'"))
+ << "Single quotes handled properly #1";
+}
+
+TEST(MimeType, SingleQuotes2)
+{
+ const auto in = u"text/html;charset='gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset='gbk"))
+ << "Single quotes handled properly #2";
+}
+
+TEST(MimeType, SingleQuotes3)
+{
+ const auto in = u"text/html;charset=gbk'"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk'"))
+ << "Single quotes handled properly #3";
+}
+
+TEST(MimeType, SingleQuotes4)
+{
+ const auto in = u"text/html;charset=';charset=GBK"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset='"))
+ << "Single quotes handled properly #4";
+}
+
+TEST(MimeType, SingleQuotes5)
+{
+ const auto in = u"text/html;charset=''';charset=GBK"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset='''"))
+ << "Single quotes handled properly #5";
+}
+
+TEST(MimeType, DoubleQuotes1)
+{
+ const auto in = u"text/html;charset=\"gbk\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Double quotes handled properly #1";
+}
+
+TEST(MimeType, DoubleQuotes2)
+{
+ const auto in = u"text/html;charset=\"gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Double quotes handled properly #2";
+}
+
+TEST(MimeType, DoubleQuotes3)
+{
+ const auto in = u"text/html;charset=gbk\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"gbk\\\"\""))
+ << "Double quotes handled properly #3";
+}
+
+TEST(MimeType, DoubleQuotes4)
+{
+ const auto in = u"text/html;charset=\" gbk\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" gbk\""))
+ << "Double quotes handled properly #4";
+}
+
+TEST(MimeType, DoubleQuotes5)
+{
+ const auto in = u"text/html;charset=\"gbk \""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"gbk \""))
+ << "Double quotes handled properly #5";
+}
+
+TEST(MimeType, DoubleQuotes6)
+{
+ const auto in = u"text/html;charset=\"\\ gbk\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\" gbk\""))
+ << "Double quotes handled properly #6";
+}
+
+TEST(MimeType, DoubleQuotes7)
+{
+ const auto in = u"text/html;charset=\"\\g\\b\\k\""_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Double quotes handled properly #7";
+}
+
+TEST(MimeType, DoubleQuotes8)
+{
+ const auto in = u"text/html;charset=\"gbk\"x"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=gbk"))
+ << "Double quotes handled properly #8";
+}
+
+TEST(MimeType, DoubleQuotes9)
+{
+ const auto in = u"text/html;charset=\"\";charset=GBK"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"\""))
+ << "Double quotes handled properly #9";
+}
+
+TEST(MimeType, DoubleQuotes10)
+{
+ const auto in = u"text/html;charset=\";charset=GBK"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\";charset=GBK\""))
+ << "Double quotes handled properly #10";
+}
+
+TEST(MimeType, UnexpectedCodePoints)
+{
+ const auto in = u"text/html;charset={gbk}"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"{gbk}\""))
+ << "Unexpected code points handled properly";
+}
+
+TEST(MimeType, LongTypesSubtypesAccepted)
+{
+ const auto in = nsLiteralString(
+ u"01234567890123456789012345678901234567890123456789012345678901234567890"
+ u"1"
+ "2345678901234567890123456789012345678901234567890123456789/"
+ "012345678901234567890123456789012345678901234567890123456789012345678901"
+ "2345678901234567890123456789012345678901234567890123456789");
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals(in))
+ << "Long type/subtype accepted";
+}
+
+TEST(MimeType, LongParametersAccepted)
+{
+ const auto in = nsLiteralString(
+ u"text/"
+ "html;"
+ "012345678901234567890123456789012345678901234567890123456789012345678901"
+ "2345678901234567890123456789012345678901234567890123456789=x;charset="
+ "gbk");
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals(in))
+ << "Long parameters accepted";
+}
+
+TEST(MimeType, AllValidCharactersAccepted1)
+{
+ const auto in = nsLiteralString(
+ u"x/x;x=\"\t "
+ u"!\\\"#$%&'()*+,-./"
+ u"0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`"
+ u"abcdefghijklmnopqrstuvwxyz{|}~"
+ u"\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A"
+ u"\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094\u0095"
+ u"\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E\u009F\u00A0"
+ u"\u00A1\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A8\u00A9\u00AA\u00AB"
+ u"\u00AC\u00AD\u00AE\u00AF\u00B0\u00B1\u00B2\u00B3\u00B4\u00B5\u00B6"
+ u"\u00B7\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF\u00C0\u00C1"
+ u"\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC"
+ u"\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7"
+ u"\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF\u00E0\u00E1\u00E2"
+ u"\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED"
+ u"\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8"
+ u"\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF\"");
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.Equals(in))
+ << "All valid characters accepted #1";
+}
+
+TEST(MimeType, CaseNormalization1)
+{
+ const auto in = u"TEXT/PLAIN;CHARSET=TEST"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/plain;charset=TEST"))
+ << "Case normalized properly #1";
+}
+
+TEST(MimeType, CaseNormalization2)
+{
+ const auto in = nsLiteralString(
+ u"!#$%&'*+-.^_`|~"
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"
+ "!#$%&'*+-.^_`|~"
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz;!#$%&'*+-"
+ ".^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=!#$"
+ "%&'*+-.^_`|~"
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral(
+ "!#$%&'*+-.^_`|~"
+ "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/"
+ "!#$%&'*+-.^_`|~"
+ "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;!#$%&'*+-"
+ ".^_`|~0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz=!#$"
+ "%&'*+-.^_`|~"
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"))
+ << "Case normalized properly #2";
+}
+
+TEST(MimeType, LegacyCommentSyntax1)
+{
+ const auto in = u"text/html;charset=gbk("_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;charset=\"gbk(\""))
+ << "Legacy comment syntax #1";
+}
+
+TEST(MimeType, LegacyCommentSyntax2)
+{
+ const auto in = u"text/html;x=(;charset=gbk"_ns;
+ UniquePtr<MimeType> parsed = MimeType::Parse(in);
+ ASSERT_TRUE(parsed)
+ << "Parsing succeeded";
+ nsAutoString out;
+ parsed->Serialize(out);
+ ASSERT_TRUE(out.EqualsLiteral("text/html;x=\"(\";charset=gbk"))
+ << "Legacy comment syntax #2";
+}
diff --git a/dom/base/test/gtest/TestParser.cpp b/dom/base/test/gtest/TestParser.cpp
new file mode 100644
index 0000000000..d9240cced7
--- /dev/null
+++ b/dom/base/test/gtest/TestParser.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "mozilla/dom/DOMParser.h"
+#include "mozilla/dom/Document.h"
+#include "nsIDocumentEncoder.h"
+#include "mozilla/ErrorResult.h"
+
+// This is a test for mozilla::dom::DOMParser::CreateWithoutGlobal() which was
+// implemented for use in Thunderbird's MailNews module.
+
+// int main(int argc, char** argv)
+TEST(TestParser, TestParserMain)
+{
+ bool allTestsPassed = false;
+ constexpr auto htmlInput =
+ u"<html><head>"
+ "<meta http-equiv=\"content-type\" content=\"text/html; charset=\">"
+ "</head><body>Hello <b>Thunderbird!</b></body></html>"_ns;
+
+ do {
+ // Parse the HTML source.
+ mozilla::IgnoredErrorResult rv2;
+ RefPtr<mozilla::dom::DOMParser> parser =
+ mozilla::dom::DOMParser::CreateWithoutGlobal(rv2);
+ if (rv2.Failed()) break;
+ nsCOMPtr<mozilla::dom::Document> document = parser->ParseFromString(
+ htmlInput, mozilla::dom::SupportedType::Text_html, rv2);
+ if (rv2.Failed()) break;
+
+ // Serialize it back to HTML source again.
+ nsCOMPtr<nsIDocumentEncoder> encoder =
+ do_createDocumentEncoder("text/html");
+ if (!encoder) break;
+ nsresult rv =
+ encoder->Init(document, u"text/html"_ns, nsIDocumentEncoder::OutputRaw);
+ if (NS_FAILED(rv)) break;
+ nsString parsed;
+ rv = encoder->EncodeToString(parsed);
+ if (NS_FAILED(rv)) break;
+
+ EXPECT_TRUE(parsed.Equals(htmlInput));
+ allTestsPassed = true;
+ } while (false);
+
+ EXPECT_TRUE(allTestsPassed);
+}
diff --git a/dom/base/test/gtest/TestPlainTextSerializer.cpp b/dom/base/test/gtest/TestPlainTextSerializer.cpp
new file mode 100644
index 0000000000..10a69fd318
--- /dev/null
+++ b/dom/base/test/gtest/TestPlainTextSerializer.cpp
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsString.h"
+#include "nsIDocumentEncoder.h"
+#include "nsCRT.h"
+#include "nsIParserUtils.h"
+
+const uint32_t kDefaultWrapColumn = 72;
+
+void ConvertBufToPlainText(nsString& aConBuf, int aFlag, uint32_t aWrapColumn) {
+ nsCOMPtr<nsIParserUtils> utils = do_GetService(NS_PARSERUTILS_CONTRACTID);
+ utils->ConvertToPlainText(aConBuf, aFlag, aWrapColumn, aConBuf);
+}
+
+// Test for ASCII with format=flowed; delsp=yes
+TEST(PlainTextSerializer, ASCIIWithFlowedDelSp)
+{
+ nsString test;
+ nsString result;
+
+ test.AssignLiteral(
+ "<html><body>"
+ "Firefox Firefox Firefox Firefox "
+ "Firefox Firefox Firefox Firefox "
+ "Firefox Firefox Firefox Firefox"
+ "</body></html>");
+
+ ConvertBufToPlainText(test,
+ nsIDocumentEncoder::OutputFormatted |
+ nsIDocumentEncoder::OutputCRLineBreak |
+ nsIDocumentEncoder::OutputLFLineBreak |
+ nsIDocumentEncoder::OutputFormatFlowed |
+ nsIDocumentEncoder::OutputFormatDelSp,
+ kDefaultWrapColumn);
+
+ // create result case
+ result.AssignLiteral(
+ "Firefox Firefox Firefox Firefox "
+ "Firefox Firefox Firefox Firefox "
+ "Firefox \r\nFirefox Firefox Firefox\r\n");
+
+ ASSERT_TRUE(test.Equals(result))
+ << "Wrong HTML to ASCII text serialization with format=flowed; delsp=yes";
+}
+
+// Test for CJK with format=flowed; delsp=yes
+TEST(PlainTextSerializer, CJKWithFlowedDelSp)
+{
+ nsString test;
+ nsString result;
+
+ test.AssignLiteral("<html><body>");
+ for (uint32_t i = 0; i < 40; i++) {
+ // Insert Kanji (U+5341)
+ test.Append(0x5341);
+ }
+ test.AppendLiteral("</body></html>");
+
+ ConvertBufToPlainText(test,
+ nsIDocumentEncoder::OutputFormatted |
+ nsIDocumentEncoder::OutputCRLineBreak |
+ nsIDocumentEncoder::OutputLFLineBreak |
+ nsIDocumentEncoder::OutputFormatFlowed |
+ nsIDocumentEncoder::OutputFormatDelSp,
+ kDefaultWrapColumn);
+
+ // create result case
+ for (uint32_t i = 0; i < 36; i++) {
+ result.Append(0x5341);
+ }
+ result.AppendLiteral(" \r\n");
+ for (uint32_t i = 0; i < 4; i++) {
+ result.Append(0x5341);
+ }
+ result.AppendLiteral("\r\n");
+
+ ASSERT_TRUE(test.Equals(result))
+ << "Wrong HTML to CJK text serialization with format=flowed; delsp=yes";
+}
+
+// Test for CJK with DisallowLineBreaking
+TEST(PlainTextSerializer, CJKWithDisallowLineBreaking)
+{
+ nsString test;
+ nsString result;
+
+ test.AssignLiteral("<html><body>");
+ for (uint32_t i = 0; i < 400; i++) {
+ // Insert Kanji (U+5341)
+ test.Append(0x5341);
+ }
+ test.AppendLiteral("</body></html>");
+
+ ConvertBufToPlainText(test,
+ nsIDocumentEncoder::OutputFormatted |
+ nsIDocumentEncoder::OutputCRLineBreak |
+ nsIDocumentEncoder::OutputLFLineBreak |
+ nsIDocumentEncoder::OutputFormatFlowed |
+ nsIDocumentEncoder::OutputDisallowLineBreaking,
+ kDefaultWrapColumn);
+
+ // create result case
+ for (uint32_t i = 0; i < 400; i++) {
+ result.Append(0x5341);
+ }
+ result.AppendLiteral("\r\n");
+
+ ASSERT_TRUE(test.Equals(result))
+ << "Wrong HTML to CJK text serialization with OutputDisallowLineBreaking";
+}
+
+// Test for Latin with DisallowLineBreaking
+TEST(PlainTextSerializer, LatinWithDisallowLineBreaking)
+{
+ nsString test;
+ test.AssignLiteral("<html><body>");
+ for (uint32_t i = 0; i < 400; i++) {
+ // Insert á (Latin Small Letter a with Acute) (U+00E1)
+ test.Append(0x00E1);
+ }
+ test.AppendLiteral("</body></html>\r\n");
+
+ ConvertBufToPlainText(test,
+ nsIDocumentEncoder::OutputFormatted |
+ nsIDocumentEncoder::OutputCRLineBreak |
+ nsIDocumentEncoder::OutputLFLineBreak |
+ nsIDocumentEncoder::OutputFormatFlowed |
+ nsIDocumentEncoder::OutputDisallowLineBreaking,
+ kDefaultWrapColumn);
+
+ // Create expect case.
+ nsString expect;
+ for (uint32_t i = 0; i < 400; i++) {
+ expect.Append(0x00E1);
+ }
+ expect.AppendLiteral(" \r\n\r\n");
+
+ ASSERT_TRUE(test.Equals(expect))
+ << "Wrong HTML to Latin text serialization with OutputDisallowLineBreaking";
+}
+
+// Test for ASCII with format=flowed; and quoted lines in preformatted span.
+TEST(PlainTextSerializer, PreformatFlowedQuotes)
+{
+ nsString test;
+ nsString result;
+
+ test.AssignLiteral(
+ "<html><body>"
+ "<span style=\"white-space: pre-wrap;\" _moz_quote=\"true\">"
+ "&gt; Firefox Firefox Firefox Firefox <br>"
+ "&gt; Firefox Firefox Firefox Firefox<br>"
+ "&gt;<br>"
+ "&gt;&gt; Firefox Firefox Firefox Firefox <br>"
+ "&gt;&gt; Firefox Firefox Firefox Firefox<br>"
+ "</span></body></html>");
+
+ ConvertBufToPlainText(test,
+ nsIDocumentEncoder::OutputFormatted |
+ nsIDocumentEncoder::OutputCRLineBreak |
+ nsIDocumentEncoder::OutputLFLineBreak |
+ nsIDocumentEncoder::OutputFormatFlowed,
+ kDefaultWrapColumn);
+
+ // create result case
+ result.AssignLiteral(
+ "> Firefox Firefox Firefox Firefox \r\n"
+ "> Firefox Firefox Firefox Firefox\r\n"
+ ">\r\n"
+ ">> Firefox Firefox Firefox Firefox \r\n"
+ ">> Firefox Firefox Firefox Firefox\r\n");
+
+ ASSERT_TRUE(test.Equals(result))
+ << "Wrong HTML to ASCII text serialization "
+ "with format=flowed; and quoted "
+ "lines";
+}
+
+TEST(PlainTextSerializer, PrettyPrintedHtml)
+{
+ nsString test;
+ test.AppendLiteral("<html>" NS_LINEBREAK "<body>" NS_LINEBREAK
+ " first<br>" NS_LINEBREAK " second<br>" NS_LINEBREAK
+ "</body>" NS_LINEBREAK "</html>");
+
+ ConvertBufToPlainText(test, 0, kDefaultWrapColumn);
+ ASSERT_TRUE(test.EqualsLiteral("first" NS_LINEBREAK "second" NS_LINEBREAK))
+ << "Wrong prettyprinted html to text serialization";
+}
+
+TEST(PlainTextSerializer, PreElement)
+{
+ nsString test;
+ test.AppendLiteral("<html>" NS_LINEBREAK "<body>" NS_LINEBREAK
+ "<pre>" NS_LINEBREAK " first" NS_LINEBREAK
+ " second" NS_LINEBREAK "</pre>" NS_LINEBREAK
+ "</body>" NS_LINEBREAK "</html>");
+
+ ConvertBufToPlainText(test, 0, kDefaultWrapColumn);
+ ASSERT_TRUE(test.EqualsLiteral(" first" NS_LINEBREAK
+ " second" NS_LINEBREAK NS_LINEBREAK))
+ << "Wrong prettyprinted html to text serialization";
+}
+
+TEST(PlainTextSerializer, BlockElement)
+{
+ nsString test;
+ test.AppendLiteral("<html>" NS_LINEBREAK "<body>" NS_LINEBREAK
+ "<div>" NS_LINEBREAK " first" NS_LINEBREAK
+ "</div>" NS_LINEBREAK "<div>" NS_LINEBREAK
+ " second" NS_LINEBREAK "</div>" NS_LINEBREAK
+ "</body>" NS_LINEBREAK "</html>");
+
+ ConvertBufToPlainText(test, 0, kDefaultWrapColumn);
+ ASSERT_TRUE(test.EqualsLiteral("first" NS_LINEBREAK "second" NS_LINEBREAK))
+ << "Wrong prettyprinted html to text serialization";
+}
+
+TEST(PlainTextSerializer, PreWrapElementForThunderbird)
+{
+ // This test examines the magic pre-wrap setup that Thunderbird relies on.
+ nsString test;
+ test.AppendLiteral("<html>" NS_LINEBREAK
+ "<body style=\"white-space: pre-wrap;\">" NS_LINEBREAK
+ "<pre>" NS_LINEBREAK
+ " first line is too long" NS_LINEBREAK
+ " second line is even loooonger " NS_LINEBREAK
+ "</pre>" NS_LINEBREAK "</body>" NS_LINEBREAK "</html>");
+
+ const uint32_t wrapColumn = 10;
+ ConvertBufToPlainText(test, nsIDocumentEncoder::OutputWrap, wrapColumn);
+ // "\n\n first\nline is\ntoo long\n second\nline is\neven\nloooonger\n\n\n"
+ ASSERT_TRUE(test.EqualsLiteral(
+ NS_LINEBREAK NS_LINEBREAK
+ " first" NS_LINEBREAK "line is" NS_LINEBREAK "too long" NS_LINEBREAK
+ " second" NS_LINEBREAK "line is" NS_LINEBREAK "even" NS_LINEBREAK
+ "loooonger" NS_LINEBREAK NS_LINEBREAK NS_LINEBREAK))
+ << "Wrong prettyprinted html to text serialization";
+}
+
+TEST(PlainTextSerializer, Simple)
+{
+ nsString test;
+ test.AppendLiteral(
+ "<html><base>base</base><head><span>span</span></head>"
+ "<body>body</body></html>");
+ ConvertBufToPlainText(test, 0, kDefaultWrapColumn);
+ ASSERT_TRUE(test.EqualsLiteral("basespanbody"))
+ << "Wrong html to text serialization";
+}
+
+TEST(PlainTextSerializer, OneHundredAndOneOL)
+{
+ nsAutoString test;
+ test.AppendLiteral(
+ "<html>"
+ "<body>"
+ "<ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><"
+ "ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><"
+ "ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><"
+ "ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><"
+ "ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><"
+ "ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol><ol></ol></ol></ol></"
+ "ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></"
+ "ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></"
+ "ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></"
+ "ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></"
+ "ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></"
+ "ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></"
+ "ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></ol></"
+ "ol></ol><li>X</li></ol>"
+ "</body>"
+ "</html>");
+
+ ConvertBufToPlainText(test, nsIDocumentEncoder::OutputFormatted,
+ kDefaultWrapColumn);
+
+ nsAutoString expected;
+ expected.AppendLiteral(" 1. X" NS_LINEBREAK);
+ ASSERT_EQ(test, expected);
+}
+
+TEST(PlainTextSerializer, BlockQuoteCite)
+{
+ nsAutoString test;
+ test.AppendLiteral(u"<blockquote type=cite>hello world</blockquote>");
+
+ const uint32_t wrapColumn = 10;
+ ConvertBufToPlainText(test,
+ nsIDocumentEncoder::OutputFormatted |
+ nsIDocumentEncoder::OutputFormatFlowed |
+ nsIDocumentEncoder::OutputCRLineBreak |
+ nsIDocumentEncoder::OutputLFLineBreak,
+ wrapColumn);
+
+ constexpr auto expect = NS_LITERAL_STRING_FROM_CSTRING(
+ "> hello \r\n"
+ "> world\r\n");
+
+ ASSERT_TRUE(test.Equals(expect))
+ << "Wrong blockquote cite to text serialization";
+}
diff --git a/dom/base/test/gtest/TestScheduler.cpp b/dom/base/test/gtest/TestScheduler.cpp
new file mode 100644
index 0000000000..00c578e556
--- /dev/null
+++ b/dom/base/test/gtest/TestScheduler.cpp
@@ -0,0 +1,348 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/dom/CCGCScheduler.h"
+#include "mozilla/TimeStamp.h"
+
+// This is a test for mozilla::CCGCScheduler.
+
+using namespace mozilla;
+
+static TimeDuration kOneSecond = TimeDuration::FromSeconds(1);
+static TimeDuration kTenthSecond = TimeDuration::FromSeconds(0.1);
+static TimeDuration kFrameDuration = TimeDuration::FromSeconds(1.0 / 60.0);
+
+static mozilla::TimeStamp sNow = TimeStamp::Now();
+
+static mozilla::TimeStamp AdvanceTime(TimeDuration aDuration) {
+ sNow += aDuration;
+ return sNow;
+}
+
+static TimeStamp Now() { return sNow; }
+
+static uint32_t sSuspected = 0;
+
+static uint32_t SuspectedCCObjects() { return sSuspected; }
+static void SetNumSuspected(uint32_t n) { sSuspected = n; }
+static void SuspectMore(uint32_t n) { sSuspected += n; }
+
+using CCRunnerState = mozilla::CCGCScheduler::CCRunnerState;
+
+class TestGC {
+ protected:
+ CCGCScheduler& mScheduler;
+
+ public:
+ explicit TestGC(CCGCScheduler& aScheduler) : mScheduler(aScheduler) {}
+ void Run(int aNumSlices);
+};
+
+void TestGC::Run(int aNumSlices) {
+ // Make the purple buffer nearly empty so it is itself not an adequate reason
+ // for wanting a CC.
+ static_assert(3 < mozilla::kCCPurpleLimit);
+ SetNumSuspected(3);
+
+ // Running the GC should not influence whether a CC is currently seen as
+ // needed. But the first time we run GC, it will be false; later, we will
+ // have run a GC and set it to true.
+ CCReason neededCCAtStartOfGC =
+ mScheduler.IsCCNeeded(Now(), SuspectedCCObjects());
+
+ mScheduler.NoteGCBegin(JS::GCReason::API);
+
+ for (int slice = 0; slice < aNumSlices; slice++) {
+ EXPECT_TRUE(mScheduler.InIncrementalGC());
+ TimeStamp idleDeadline = Now() + kTenthSecond;
+ js::SliceBudget budget =
+ mScheduler.ComputeInterSliceGCBudget(idleDeadline, Now());
+ TimeDuration budgetDuration =
+ TimeDuration::FromMilliseconds(budget.timeBudget());
+ EXPECT_NEAR(budgetDuration.ToSeconds(), 0.1, 1.e-6);
+ // Pretend the GC took exactly the budget.
+ AdvanceTime(budgetDuration);
+
+ EXPECT_EQ(mScheduler.IsCCNeeded(Now(), SuspectedCCObjects()),
+ neededCCAtStartOfGC);
+
+ // Mutator runs for 1 second.
+ AdvanceTime(kOneSecond);
+ }
+
+ mScheduler.NoteGCEnd();
+ mScheduler.SetNeedsFullGC(false);
+}
+
+class TestCC {
+ protected:
+ CCGCScheduler& mScheduler;
+
+ public:
+ explicit TestCC(CCGCScheduler& aScheduler) : mScheduler(aScheduler) {}
+
+ void Run(int aNumSlices) {
+ Prepare();
+ MaybePokeCC();
+ TimerFires(aNumSlices);
+ EndCycleCollectionCallback();
+ KillCCRunner();
+ }
+
+ virtual void Prepare() = 0;
+ virtual void MaybePokeCC();
+ virtual void TimerFires(int aNumSlices);
+ virtual void RunSlices(int aNumSlices);
+ virtual void RunSlice(TimeStamp aCCStartTime, TimeStamp aPrevSliceEnd,
+ int aSliceNum, int aNumSlices) = 0;
+ virtual void ForgetSkippable();
+ virtual void EndCycleCollectionCallback();
+ virtual void KillCCRunner();
+};
+
+void TestCC::MaybePokeCC() {
+ // nsJSContext::MaybePokeCC
+
+ // In all tests so far, we will be running this just after a GC.
+ CCReason reason = mScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects());
+ EXPECT_EQ(reason, CCReason::GC_FINISHED);
+
+ mScheduler.InitCCRunnerStateMachine(CCRunnerState::ReducePurple, reason);
+ EXPECT_TRUE(mScheduler.IsEarlyForgetSkippable());
+}
+
+void TestCC::TimerFires(int aNumSlices) {
+ // Series of CCRunner timer fires.
+ CCRunnerStep step;
+
+ while (true) {
+ SuspectMore(1000);
+ TimeStamp idleDeadline = Now() + kOneSecond;
+ step =
+ mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
+ // Should first see a series of ForgetSkippable actions.
+ if (step.mAction != CCRunnerAction::ForgetSkippable ||
+ step.mParam.mRemoveChildless != KeepChildless) {
+ break;
+ }
+ EXPECT_EQ(step.mYield, Yield);
+ ForgetSkippable();
+ }
+
+ while (step.mYield == Continue) {
+ TimeStamp idleDeadline = Now() + kOneSecond;
+ step =
+ mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
+ }
+ EXPECT_EQ(step.mAction, CCRunnerAction::ForgetSkippable);
+ EXPECT_EQ(step.mParam.mRemoveChildless, RemoveChildless);
+ ForgetSkippable();
+
+ TimeStamp idleDeadline = Now() + kOneSecond;
+ step = mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
+ EXPECT_EQ(step.mAction, CCRunnerAction::CleanupContentUnbinder);
+ step = mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
+ EXPECT_EQ(step.mAction, CCRunnerAction::CleanupDeferred);
+
+ mScheduler.NoteCCBegin(CCReason::API, Now(), 0, sSuspected, 0);
+ RunSlices(aNumSlices);
+}
+
+void TestCC::ForgetSkippable() {
+ uint32_t suspectedBefore = sSuspected;
+ // ...ForgetSkippable would happen here...
+ js::SliceBudget budget =
+ mScheduler.ComputeForgetSkippableBudget(Now(), Now() + kTenthSecond);
+ EXPECT_NEAR(budget.timeBudget(), kTenthSecond.ToMilliseconds(), 1);
+ AdvanceTime(kTenthSecond);
+ mScheduler.NoteForgetSkippableComplete(Now(), suspectedBefore,
+ SuspectedCCObjects());
+}
+
+void TestCC::RunSlices(int aNumSlices) {
+ TimeStamp ccStartTime = Now();
+ TimeStamp prevSliceEnd = ccStartTime;
+ for (int ccslice = 0; ccslice < aNumSlices; ccslice++) {
+ RunSlice(ccStartTime, prevSliceEnd, ccslice, aNumSlices);
+ prevSliceEnd = Now();
+ }
+
+ SetNumSuspected(0);
+}
+
+void TestCC::EndCycleCollectionCallback() {
+ // nsJSContext::EndCycleCollectionCallback
+ CycleCollectorResults results;
+ results.mFreedGCed = 10;
+ results.mFreedJSZones = 2;
+ mScheduler.NoteCCEnd(results, Now(), TimeDuration());
+
+ // Because > 0 zones were freed.
+ EXPECT_TRUE(mScheduler.NeedsGCAfterCC());
+}
+
+void TestCC::KillCCRunner() {
+ // nsJSContext::KillCCRunner
+ mScheduler.KillCCRunner();
+}
+
+class TestIdleCC : public TestCC {
+ public:
+ explicit TestIdleCC(CCGCScheduler& aScheduler) : TestCC(aScheduler) {}
+
+ void Prepare() override;
+ void RunSlice(TimeStamp aCCStartTime, TimeStamp aPrevSliceEnd, int aSliceNum,
+ int aNumSlices) override;
+};
+
+void TestIdleCC::Prepare() { EXPECT_TRUE(!mScheduler.InIncrementalGC()); }
+
+void TestIdleCC::RunSlice(TimeStamp aCCStartTime, TimeStamp aPrevSliceEnd,
+ int aSliceNum, int aNumSlices) {
+ CCRunnerStep step;
+ TimeStamp idleDeadline = Now() + kTenthSecond;
+
+ // The scheduler should request a CycleCollect slice.
+ step = mScheduler.AdvanceCCRunner(idleDeadline, Now(), SuspectedCCObjects());
+ EXPECT_EQ(step.mAction, CCRunnerAction::CycleCollect);
+
+ // nsJSContext::RunCycleCollectorSlice
+
+ EXPECT_FALSE(mScheduler.InIncrementalGC());
+ bool preferShorter;
+ js::SliceBudget budget = mScheduler.ComputeCCSliceBudget(
+ idleDeadline, aCCStartTime, aPrevSliceEnd, Now(), &preferShorter);
+ // The scheduler will set the budget to our deadline (0.1sec in the future).
+ EXPECT_NEAR(budget.timeBudget(), kTenthSecond.ToMilliseconds(), 1);
+ EXPECT_FALSE(preferShorter);
+
+ AdvanceTime(kTenthSecond);
+}
+
+class TestNonIdleCC : public TestCC {
+ public:
+ explicit TestNonIdleCC(CCGCScheduler& aScheduler) : TestCC(aScheduler) {}
+
+ void Prepare() override;
+ void RunSlice(TimeStamp aCCStartTime, TimeStamp aPrevSliceEnd, int aSliceNum,
+ int aNumSlices) override;
+};
+
+void TestNonIdleCC::Prepare() {
+ EXPECT_TRUE(!mScheduler.InIncrementalGC());
+
+ // Advance time by an hour to give time for a user event in the past.
+ AdvanceTime(TimeDuration::FromSeconds(3600));
+}
+
+void TestNonIdleCC::RunSlice(TimeStamp aCCStartTime, TimeStamp aPrevSliceEnd,
+ int aSliceNum, int aNumSlices) {
+ CCRunnerStep step;
+ TimeStamp nullDeadline;
+
+ // The scheduler should tell us to run a slice of cycle collection.
+ step = mScheduler.AdvanceCCRunner(nullDeadline, Now(), SuspectedCCObjects());
+ EXPECT_EQ(step.mAction, CCRunnerAction::CycleCollect);
+
+ // nsJSContext::RunCycleCollectorSlice
+
+ EXPECT_FALSE(mScheduler.InIncrementalGC());
+
+ bool preferShorter;
+ js::SliceBudget budget = mScheduler.ComputeCCSliceBudget(
+ nullDeadline, aCCStartTime, aPrevSliceEnd, Now(), &preferShorter);
+ if (aSliceNum == 0) {
+ // First slice of the CC, so always use the baseBudget which is
+ // kICCSliceBudget (3ms) for a non-idle slice.
+ EXPECT_NEAR(budget.timeBudget(), kICCSliceBudget.ToMilliseconds(), 0.1);
+ } else if (aSliceNum == 1) {
+ // Second slice still uses the baseBudget, since not much time has passed
+ // so none of the lengthening mechanisms have kicked in yet.
+ EXPECT_NEAR(budget.timeBudget(), kICCSliceBudget.ToMilliseconds(), 0.1);
+ } else if (aSliceNum == 2) {
+ // We're not overrunning kMaxICCDuration, so we don't go unlimited.
+ EXPECT_FALSE(budget.isUnlimited());
+ // This slice is delayed by twice the allowed amount. Slice time should be
+ // doubled.
+ EXPECT_NEAR(budget.timeBudget(), kICCSliceBudget.ToMilliseconds() * 2, 0.1);
+ } else {
+ // We're not overrunning kMaxICCDuration, so we don't go unlimited.
+ EXPECT_FALSE(budget.isUnlimited());
+
+ // These slices are not delayed, but enough time has passed that the
+ // dominating factor is now the linear ramp up to max slice time at the
+ // halfway point to kMaxICCDuration.
+ EXPECT_TRUE(budget.timeBudget() > kICCSliceBudget.ToMilliseconds());
+ EXPECT_TRUE(budget.timeBudget() <=
+ MainThreadIdlePeriod::GetLongIdlePeriod());
+ }
+ EXPECT_TRUE(preferShorter); // Non-idle prefers shorter slices
+
+ AdvanceTime(TimeDuration::FromMilliseconds(budget.timeBudget()));
+ if (aSliceNum == 1) {
+ // Delay the third slice (only).
+ AdvanceTime(kICCIntersliceDelay * 2);
+ }
+}
+
+// Do a GC then CC then GC.
+static bool BasicScenario(CCGCScheduler& aScheduler, TestGC* aTestGC,
+ TestCC* aTestCC) {
+ // Run a 10-slice incremental GC.
+ aTestGC->Run(10);
+
+ // After a GC, the scheduler should decide to do a full CC regardless of the
+ // number of purple buffer entries.
+ SetNumSuspected(3);
+ EXPECT_EQ(aScheduler.IsCCNeeded(Now(), SuspectedCCObjects()),
+ CCReason::GC_FINISHED);
+
+ // Now we should want to CC.
+ EXPECT_EQ(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()),
+ CCReason::GC_FINISHED);
+
+ // Do a 5-slice CC.
+ aTestCC->Run(5);
+
+ // Not enough suspected objects to deserve a CC.
+ EXPECT_EQ(aScheduler.IsCCNeeded(Now(), SuspectedCCObjects()),
+ CCReason::NO_REASON);
+ EXPECT_EQ(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()),
+ CCReason::NO_REASON);
+ SetNumSuspected(10000);
+
+ // We shouldn't want to CC again yet, it's too soon.
+ EXPECT_EQ(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()),
+ CCReason::NO_REASON);
+ AdvanceTime(mozilla::kCCDelay);
+
+ // *Now* it's time for another CC.
+ EXPECT_EQ(aScheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()),
+ CCReason::MANY_SUSPECTED);
+
+ // Run a 3-slice incremental GC.
+ EXPECT_TRUE(!aScheduler.InIncrementalGC());
+ aTestGC->Run(3);
+
+ return true;
+}
+
+static CCGCScheduler scheduler;
+static TestGC gc(scheduler);
+static TestIdleCC ccIdle(scheduler);
+static TestNonIdleCC ccNonIdle(scheduler);
+
+TEST(TestScheduler, Idle)
+{
+ // Cannot CC until we GC once.
+ EXPECT_EQ(scheduler.ShouldScheduleCC(Now(), SuspectedCCObjects()),
+ CCReason::NO_REASON);
+
+ EXPECT_TRUE(BasicScenario(scheduler, &gc, &ccIdle));
+}
+
+TEST(TestScheduler, NonIdle)
+{ EXPECT_TRUE(BasicScenario(scheduler, &gc, &ccNonIdle)); }
diff --git a/dom/base/test/gtest/TestXMLSerializerNoBreakLink.cpp b/dom/base/test/gtest/TestXMLSerializerNoBreakLink.cpp
new file mode 100644
index 0000000000..a63410303e
--- /dev/null
+++ b/dom/base/test/gtest/TestXMLSerializerNoBreakLink.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "nsCOMPtr.h"
+#include "nsIDocumentEncoder.h"
+#include "nsString.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/DOMParser.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+// Test that serialising some DOM doesn't destroy links by word-wrapping long
+// href values containing spaces.
+TEST(TestXMLSerializerNoBreakLink, TestXMLSerializerNoBreakLinkMain)
+{
+ // Build up a stupidly-long URL with spaces. Default is to wrap at column
+ // 72, so we want to exceed that.
+ nsString longURL = u"http://www.example.com/link with spaces"_ns;
+ for (int i = 1; i < 125; ++i) {
+ longURL.Append(u' ');
+ longURL.Append(IntToTString<char16_t>(i));
+ }
+ nsString htmlInput =
+ u"<html><head>"
+ "<meta charset=\"utf-8\">"
+ "</head><body>Hello Thunderbird! <a href=\""_ns +
+ longURL + u"\">Link</a></body></html>"_ns;
+
+ // Parse HTML into a Document.
+ nsCOMPtr<Document> document;
+ {
+ IgnoredErrorResult rv;
+ RefPtr<DOMParser> parser = DOMParser::CreateWithoutGlobal(rv);
+ ASSERT_FALSE(rv.Failed());
+ document = parser->ParseFromString(htmlInput, SupportedType::Text_html, rv);
+ ASSERT_FALSE(rv.Failed());
+ }
+
+ // Serialize back in a variety of flavours and check the URL survives the
+ // round trip intact.
+ nsCString contentTypes[] = {"text/xml"_ns, "application/xml"_ns,
+ "application/xhtml+xml"_ns, "image/svg+xml"_ns,
+ "text/html"_ns};
+ for (auto const& contentType : contentTypes) {
+ uint32_t flagsToTest[] = {
+ nsIDocumentEncoder::OutputFormatted, nsIDocumentEncoder::OutputWrap,
+ nsIDocumentEncoder::OutputFormatted | nsIDocumentEncoder::OutputWrap};
+ for (uint32_t flags : flagsToTest) {
+ // Serialize doc back to HTML source again.
+ nsCOMPtr<nsIDocumentEncoder> encoder =
+ do_createDocumentEncoder(contentType.get());
+ ASSERT_TRUE(encoder);
+ nsresult rv =
+ encoder->Init(document, NS_ConvertASCIItoUTF16(contentType), flags);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+ nsString parsed;
+ rv = encoder->EncodeToString(parsed);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ // URL is intact?
+ EXPECT_TRUE(parsed.Find(longURL) != kNotFound);
+ }
+ }
+}
diff --git a/dom/base/test/gtest/TestXPathGenerator.cpp b/dom/base/test/gtest/TestXPathGenerator.cpp
new file mode 100644
index 0000000000..c9f4993179
--- /dev/null
+++ b/dom/base/test/gtest/TestXPathGenerator.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "XPathGenerator.h"
+#include "nsString.h"
+
+TEST(TestXPathGenerator, TestQuoteArgumentWithoutQuote)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"testing");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(u"\'testing\'");
+
+ nsAutoString result;
+ XPathGenerator::QuoteArgument(arg, result);
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator, TestQuoteArgumentWithSingleQuote)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"\'testing\'");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(u"\"\'testing\'\"");
+
+ nsAutoString result;
+ XPathGenerator::QuoteArgument(arg, result);
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator, TestQuoteArgumentWithDoubleQuote)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"\"testing\"");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(u"\'\"testing\"\'");
+
+ nsAutoString result;
+ XPathGenerator::QuoteArgument(arg, result);
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator, TestQuoteArgumentWithSingleAndDoubleQuote)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"\'testing\"");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(u"concat(\'\',\"\'\",\'testing\"\')");
+
+ nsAutoString result;
+ XPathGenerator::QuoteArgument(arg, result);
+ printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(),
+ NS_ConvertUTF16toUTF8(expectedResult).get());
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator,
+ TestQuoteArgumentWithDoubleQuoteAndASequenceOfSingleQuote)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"\'\'\'\'testing\"");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(u"concat(\'\',\"\'\'\'\'\",\'testing\"\')");
+
+ nsAutoString result;
+ XPathGenerator::QuoteArgument(arg, result);
+ printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(),
+ NS_ConvertUTF16toUTF8(expectedResult).get());
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator,
+ TestQuoteArgumentWithDoubleQuoteAndTwoSequencesOfSingleQuote)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"\'\'\'\'testing\'\'\'\'\'\'\"");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(
+ u"concat(\'\',\"\'\'\'\'\",\'testing\',\"\'\'\'\'\'\'\",\'\"\')");
+
+ nsAutoString result;
+ XPathGenerator::QuoteArgument(arg, result);
+ printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(),
+ NS_ConvertUTF16toUTF8(expectedResult).get());
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator,
+ TestQuoteArgumentWithDoubleQuoteAndTwoSequencesOfSingleQuoteInMiddle)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"t\'\'\'\'estin\'\'\'\'\'\'\"g");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(
+ u"concat(\'t\',\"\'\'\'\'\",\'estin\',\"\'\'\'\'\'\'\",\'\"g\')");
+
+ nsAutoString result;
+ XPathGenerator::QuoteArgument(arg, result);
+ printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(),
+ NS_ConvertUTF16toUTF8(expectedResult).get());
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator, TestEscapeNameWithNormalCharacters)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"testing");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(u"testing");
+
+ nsAutoString result;
+ XPathGenerator::EscapeName(arg, result);
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
+
+TEST(TestXPathGenerator, TestEscapeNameWithSpecialCharacters)
+{
+ nsAutoString arg;
+ arg.AssignLiteral(u"^testing!");
+
+ nsAutoString expectedResult;
+ expectedResult.AssignLiteral(u"*[local-name()=\'^testing!\']");
+
+ nsAutoString result;
+ XPathGenerator::EscapeName(arg, result);
+ printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(),
+ NS_ConvertUTF16toUTF8(expectedResult).get());
+
+ ASSERT_TRUE(expectedResult.Equals(result));
+}
diff --git a/dom/base/test/gtest/moz.build b/dom/base/test/gtest/moz.build
new file mode 100644
index 0000000000..9a767eb2ff
--- /dev/null
+++ b/dom/base/test/gtest/moz.build
@@ -0,0 +1,21 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ "TestContentUtils.cpp",
+ "TestMimeType.cpp",
+ "TestParser.cpp",
+ "TestPlainTextSerializer.cpp",
+ "TestScheduler.cpp",
+ "TestXMLSerializerNoBreakLink.cpp",
+ "TestXPathGenerator.cpp",
+]
+
+LOCAL_INCLUDES += ["/dom/base"]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+FINAL_LIBRARY = "xul-gtest"
diff --git a/dom/base/test/head.js b/dom/base/test/head.js
new file mode 100644
index 0000000000..2b39f7a7b1
--- /dev/null
+++ b/dom/base/test/head.js
@@ -0,0 +1,15 @@
+async function newFocusedWindow(trigger) {
+ let winPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
+ let delayedStartupPromise = BrowserTestUtils.waitForNewWindow();
+
+ await trigger();
+
+ let win = await winPromise;
+ // New windows get focused after the first paint, see bug 1262946
+ await BrowserTestUtils.waitForContentEvent(
+ win.gBrowser.selectedBrowser,
+ "MozAfterPaint"
+ );
+ await delayedStartupPromise;
+ return win;
+}
diff --git a/dom/base/test/iframe1_bug1640766.html b/dom/base/test/iframe1_bug1640766.html
new file mode 100644
index 0000000000..51da4f22f0
--- /dev/null
+++ b/dom/base/test/iframe1_bug1640766.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Iframe 1 for Bug 1640766</title>
+</head>
+<body>
+<div>Iframe 1</div>
+<script type="application/javascript">
+if (parent == window) {
+ let iframe = document.createElement("iframe");
+ iframe.src = "http://example.org/tests/dom/base/test/iframe2_bug1640766.html";
+ document.body.appendChild(iframe);
+} else {
+ window.onload = function() {
+ top.opener.postMessage("ready", "*");
+ };
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/iframe1_bug426646.html b/dom/base/test/iframe1_bug426646.html
new file mode 100644
index 0000000000..533e77ad4c
--- /dev/null
+++ b/dom/base/test/iframe1_bug426646.html
@@ -0,0 +1 @@
+<html><meta charset="utf-8">1st page</html>
diff --git a/dom/base/test/iframe1_bug431701.html b/dom/base/test/iframe1_bug431701.html
new file mode 100644
index 0000000000..18ecdcb795
--- /dev/null
+++ b/dom/base/test/iframe1_bug431701.html
@@ -0,0 +1 @@
+<html></html>
diff --git a/dom/base/test/iframe2_bug1640766.html b/dom/base/test/iframe2_bug1640766.html
new file mode 100644
index 0000000000..6a5ca30796
--- /dev/null
+++ b/dom/base/test/iframe2_bug1640766.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Iframe 2 for Bug 1640766</title>
+</head>
+<body>
+<div>Iframe 2</div>
+<iframe src="http://mochi.test:8888/tests/dom/base/test/iframe1_bug1640766.html"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/iframe2_bug426646.html b/dom/base/test/iframe2_bug426646.html
new file mode 100644
index 0000000000..45e85c0f13
--- /dev/null
+++ b/dom/base/test/iframe2_bug426646.html
@@ -0,0 +1 @@
+<html><meta charset="utf-8">2nd page</html>
diff --git a/dom/base/test/iframe2_bug431701.html b/dom/base/test/iframe2_bug431701.html
new file mode 100644
index 0000000000..6c963c5455
--- /dev/null
+++ b/dom/base/test/iframe2_bug431701.html
@@ -0,0 +1 @@
+<html><meta charset="UTF-8"></html>
diff --git a/dom/base/test/iframe3_bug431701.html b/dom/base/test/iframe3_bug431701.html
new file mode 100644
index 0000000000..c0aac38766
--- /dev/null
+++ b/dom/base/test/iframe3_bug431701.html
@@ -0,0 +1 @@
+<html><meta charset="ISO-8859-1"></html>
diff --git a/dom/base/test/iframe4_bug431701.xml b/dom/base/test/iframe4_bug431701.xml
new file mode 100644
index 0000000000..18ecdcb795
--- /dev/null
+++ b/dom/base/test/iframe4_bug431701.xml
@@ -0,0 +1 @@
+<html></html>
diff --git a/dom/base/test/iframe5_bug431701.xml b/dom/base/test/iframe5_bug431701.xml
new file mode 100644
index 0000000000..d761751ee1
--- /dev/null
+++ b/dom/base/test/iframe5_bug431701.xml
@@ -0,0 +1 @@
+<?xml version='1.0'?><html></html>
diff --git a/dom/base/test/iframe6_bug431701.xml b/dom/base/test/iframe6_bug431701.xml
new file mode 100644
index 0000000000..17704b893a
--- /dev/null
+++ b/dom/base/test/iframe6_bug431701.xml
@@ -0,0 +1 @@
+<?xml version='1.0' encoding='UTF-8'?><html></html>
diff --git a/dom/base/test/iframe7_bug431701.xml b/dom/base/test/iframe7_bug431701.xml
new file mode 100644
index 0000000000..73757924a7
--- /dev/null
+++ b/dom/base/test/iframe7_bug431701.xml
@@ -0,0 +1 @@
+<?xml version='1.0' encoding='ISO-8859-1'?><html></html>
diff --git a/dom/base/test/iframe_bug962251.html b/dom/base/test/iframe_bug962251.html
new file mode 100644
index 0000000000..2fa3a50dcf
--- /dev/null
+++ b/dom/base/test/iframe_bug962251.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<input id="textinput" type="text"></input>
+<input id="textinput1" type="text"></input>
+</body>
+<script>
+ var SimpleTest = parent.SimpleTest;
+
+ var ok = SimpleTest.ok;
+ var info = SimpleTest.info;
+ var is = SimpleTest.is;
+ var finish = SimpleTest.finish.bind(SimpleTest);
+
+ var input = document.getElementById("textinput");
+ input.addEventListener("focus", function(aEvent) {
+ is(aEvent.target.id, "textinput", "Input should be focused.");
+ ok(aEvent.relatedTarget === null, "The relatedTarget should be null.");
+ parent.postMessage("runNextTest", "*");
+ }, {once: true});
+ input.focus();
+</script>
+</html> \ No newline at end of file
diff --git a/dom/base/test/iframe_bug976673.html b/dom/base/test/iframe_bug976673.html
new file mode 100644
index 0000000000..92c5bf76d0
--- /dev/null
+++ b/dom/base/test/iframe_bug976673.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 976673</title>
+</head>
+<body>
+ <input id="input" onfocus="event.target.value = event.type;"
+ onblur="event.target.value = event.type;">
+ <script>
+ var input = document.getElementById("input");
+ window.addEventListener("message", function (aEvent) {
+ switch (aEvent.data) {
+ case "init":
+ input.blur();
+ input.value = "";
+ input.focus();
+ // fall through
+ case "check":
+ aEvent.source.postMessage("input-value: " + input.value, "*");
+ break;
+ }
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/iframe_main_bug1022229.html b/dom/base/test/iframe_main_bug1022229.html
new file mode 100644
index 0000000000..c89a8c9a9d
--- /dev/null
+++ b/dom/base/test/iframe_main_bug1022229.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+ var SimpleTest = parent.SimpleTest;
+
+ var ok = SimpleTest.ok;
+ var info = SimpleTest.info;
+ var finish = SimpleTest.finish.bind(SimpleTest);
+
+ var gotTargetedMessage = false;
+ window.onmessage = function(evt) {
+ var message = evt.data;
+ info("Received message: " + message);
+ switch (message) {
+ case 'targeted':
+ gotTargetedMessage = true;
+ break;
+ case 'broadcast':
+ ok(gotTargetedMessage, "Should have received targeted message");
+ finish();
+ break;
+ default:
+ ok(false, "Unexpected message: " + message);
+ break;
+ }
+ }
+</script>
+</head>
+<body>
+<iframe src="iframe_sandbox_bug1022229.html" sandbox="allow-scripts"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/iframe_meta_refresh.sjs b/dom/base/test/iframe_meta_refresh.sjs
new file mode 100644
index 0000000000..0d881be72b
--- /dev/null
+++ b/dom/base/test/iframe_meta_refresh.sjs
@@ -0,0 +1,92 @@
+/*
+ * Test server for iframe refresh from meta http-equiv
+ */
+
+const SHARED_KEY = "iframe_meta_refresh";
+const DEFAULT_STATE = { count: 0, referrers: [] };
+const REFRESH_PAGE =
+ "http://example.com/tests/dom/base/test/iframe_meta_refresh.sjs?action=test";
+
+function createContent(refresh) {
+ let metaRefresh = "";
+ let scriptMessage = "";
+
+ if (refresh) {
+ metaRefresh = `<meta http-equiv="refresh" content="0;URL=${REFRESH_PAGE}">`;
+ } else {
+ scriptMessage = `
+ <script>
+ window.addEventListener("load", function() {
+ parent.postMessage("childLoadComplete", "http://mochi.test:8888");
+ }, false);
+ </script>`;
+ }
+
+ return `<!DOCTYPE HTML>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ ${metaRefresh}
+ <title> Test referrer of meta http-equiv refresh</title>
+ </head>
+ <body>
+ ${scriptMessage}
+ </body>
+ </html>`;
+}
+
+function handleRequest(request, response) {
+ Components.utils.importGlobalProperties(["URLSearchParams"]);
+ let query = new URLSearchParams(request.queryString);
+
+ let action = query.get("action");
+
+ var referrerLevel = "none";
+ if (request.hasHeader("Referer")) {
+ let referrer = request.getHeader("Referer");
+ if (referrer.indexOf("test_meta_refresh_referrer") > 0) {
+ referrerLevel = "full";
+ } else if (referrer == "http://mochi.test:8888/") {
+ referrerLevel = "origin";
+ }
+ }
+
+ var state = getSharedState(SHARED_KEY);
+ if (state === "") {
+ state = DEFAULT_STATE;
+ } else {
+ state = JSON.parse(state);
+ }
+
+ response.setStatusLine(request.httpVersion, 200, "OK");
+
+ //avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (action === "results") {
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(JSON.stringify(state));
+ return;
+ }
+
+ if (action === "reset") {
+ //reset server state
+ setSharedState(SHARED_KEY, JSON.stringify(DEFAULT_STATE));
+ response.write("");
+ return;
+ }
+
+ if (action === "test") {
+ let load = query.get("load");
+ state.count++;
+ if (state.referrers.indexOf(referrerLevel) < 0) {
+ state.referrers.push(referrerLevel);
+ }
+
+ // Write frame content
+ response.write(createContent(load));
+ }
+
+ setSharedState(SHARED_KEY, JSON.stringify(state));
+ return;
+}
diff --git a/dom/base/test/iframe_postMessage_solidus.html b/dom/base/test/iframe_postMessage_solidus.html
new file mode 100644
index 0000000000..86f12367ec
--- /dev/null
+++ b/dom/base/test/iframe_postMessage_solidus.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+ <script type="application/javascript">
+
+ window.addEventListener('message', receiveMessage);
+ function receiveMessage(evt) {
+ window.parent.postMessage(evt.data, '*');
+ }
+
+ </script>
+</body>
+</html>
+
+
diff --git a/dom/base/test/iframe_postMessages.html b/dom/base/test/iframe_postMessages.html
new file mode 100644
index 0000000000..0b07456eb8
--- /dev/null
+++ b/dom/base/test/iframe_postMessages.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script>
+onmessage = function(e) {
+ parent.postMessage(e.data, '*', e.ports);
+}
+
+onmessageerror = function() {
+ parent.postMessage("error", '*');
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/iframe_sandbox_bug1022229.html b/dom/base/test/iframe_sandbox_bug1022229.html
new file mode 100644
index 0000000000..3d70e9d7af
--- /dev/null
+++ b/dom/base/test/iframe_sandbox_bug1022229.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+ // First send an origin-restricted message, and then send a non-restricted
+ // message to end the test promptly even in a failure mode.
+ parent.postMessage('targeted', 'http://mochi.test:8888');
+ setTimeout(function() { parent.postMessage('broadcast', '*'); }, 0);
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/base/test/iframe_shared_compartment2a.html b/dom/base/test/iframe_shared_compartment2a.html
new file mode 100644
index 0000000000..e2451367bb
--- /dev/null
+++ b/dom/base/test/iframe_shared_compartment2a.html
@@ -0,0 +1,2 @@
+<iframe src="http://mochi.test:8888/tests/dom/base/test/iframe_shared_compartment2b.html">
+</iframe>
diff --git a/dom/base/test/iframe_shared_compartment2b.html b/dom/base/test/iframe_shared_compartment2b.html
new file mode 100644
index 0000000000..64d57320f8
--- /dev/null
+++ b/dom/base/test/iframe_shared_compartment2b.html
@@ -0,0 +1,3 @@
+<script>
+window.onload = () => window.parent.parent.go(this);
+</script>
diff --git a/dom/base/test/intersectionobserver_cross_domain_iframe.html b/dom/base/test/intersectionobserver_cross_domain_iframe.html
new file mode 100644
index 0000000000..750ccaf6f2
--- /dev/null
+++ b/dom/base/test/intersectionobserver_cross_domain_iframe.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+#target5 {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 20px;
+ height: 20px;
+ background: #f00;
+}
+</style>
+<body>
+<div id="target5"></div>
+<script>
+ var io = new IntersectionObserver(function (records) {
+ console.log(records[0].rootBounds, location.href);
+ window.parent.postMessage(records[0].rootBounds == null, 'http://mochi.test:8888');
+ }, {});
+ io.observe(document.getElementById("target5"));
+</script>
+</body>
+</html>
diff --git a/dom/base/test/intersectionobserver_iframe.html b/dom/base/test/intersectionobserver_iframe.html
new file mode 100644
index 0000000000..dae0da82c9
--- /dev/null
+++ b/dom/base/test/intersectionobserver_iframe.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+#target5 {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 20px;
+ height: 20px;
+ background: #f00;
+}
+</style>
+<body>
+<div id="target5"></div>
+</body>
+</html>
diff --git a/dom/base/test/intersectionobserver_window.html b/dom/base/test/intersectionobserver_window.html
new file mode 100644
index 0000000000..826b5064eb
--- /dev/null
+++ b/dom/base/test/intersectionobserver_window.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+#target5 {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 20px;
+ height: 20px;
+ background: #f00;
+}
+</style>
+<body>
+<div id="target"></div>
+<script>
+ var io = new IntersectionObserver(function(records) {
+ var viewportWidth =
+ document.documentElement.clientWidth || document.body.clientWidth;
+ var viewportHeight =
+ document.documentElement.clientHeight || document.body.clientHeight;
+ var result = records.length === 1 &&
+ records[0].rootBounds.top === 0 &&
+ records[0].rootBounds.left === 0 &&
+ records[0].rootBounds.right === viewportWidth &&
+ records[0].rootBounds.width === viewportWidth &&
+ records[0].rootBounds.bottom === viewportHeight &&
+ records[0].rootBounds.height === viewportHeight;
+ if (!result) {
+ result = [records.length,
+ records[0].isIntersecting,
+ records[0].rootBounds.top,
+ records[0].rootBounds.left,
+ records[0].rootBounds.right,
+ records[0].rootBounds.width,
+ records[0].rootBounds.bottom,
+ records[0].rootBounds.height,
+ viewportWidth,
+ viewportHeight].join(',');
+ }
+ window.opener.postMessage(result, '*');
+ });
+ io.observe(document.getElementById("target"));
+</script>
+</body>
+</html>
diff --git a/dom/base/test/invalid_accesscontrol.resource b/dom/base/test/invalid_accesscontrol.resource
new file mode 100644
index 0000000000..aca66f6f8d
--- /dev/null
+++ b/dom/base/test/invalid_accesscontrol.resource
@@ -0,0 +1,7 @@
+:this file must be enconded in utf8
+:and its Content-Type must be equal to text/event-stream
+
+event: message
+data: 1
+
+
diff --git a/dom/base/test/invalid_accesscontrol.resource^headers^ b/dom/base/test/invalid_accesscontrol.resource^headers^
new file mode 100644
index 0000000000..d5bed552cb
--- /dev/null
+++ b/dom/base/test/invalid_accesscontrol.resource^headers^
@@ -0,0 +1,4 @@
+Access-Control-Allow-Origin: http://an.accesscrontrol.domain:80
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate
+
diff --git a/dom/base/test/jsmodules/.eslintrc.js b/dom/base/test/jsmodules/.eslintrc.js
new file mode 100644
index 0000000000..f811aa790b
--- /dev/null
+++ b/dom/base/test/jsmodules/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ parserOptions: {
+ sourceType: "module",
+ },
+};
diff --git a/dom/base/test/jsmodules/chrome.ini b/dom/base/test/jsmodules/chrome.ini
new file mode 100644
index 0000000000..2b75dab150
--- /dev/null
+++ b/dom/base/test/jsmodules/chrome.ini
@@ -0,0 +1,53 @@
+[DEFAULT]
+support-files =
+ module_setRan.js
+ module_testSyntax.js
+ module_badSyntax.js
+ module_simpleImport.js
+ module_simpleExport.js
+ module_badImport.js
+ module_simple1.js
+ module_simple2.js
+ module_simple3.js
+ module_cyclic1.js
+ module_cyclic2.js
+ module_cyclic3.js
+ module_multiImports.js
+ module_multiLargeImports.js
+ script_simple2.js
+ module_large1.js
+ module_large2.js
+ module_large3.js
+ module_extractIntroType.js
+ iframe_extractIntroType.html
+ module_missingImport.js
+
+[test_moduleScriptsRun.html]
+[test_moduleParsedAsModule.html]
+[test_scriptNotParsedAsModule.html]
+[test_typeAttrCaseInsensitive.html]
+[test_moduleNotFound.html]
+[test_import_meta_resolve.html]
+[test_importNotFound.html]
+[test_syntaxError.html]
+[test_syntaxErrorAsync.html]
+[test_syntaxErrorInline.html]
+[test_syntaxErrorInlineAsync.html]
+[test_simpleImport.html]
+[test_cyclicImport.html]
+[test_importResolveFailed.html]
+[test_multiTopLevelImports.html]
+[test_multiModuleImports.html]
+[test_multiAsyncImports.html]
+[test_scriptModuleOrder.html]
+[test_toplevelModuleMemoization.html]
+[test_importedModuleMemoization.html]
+[test_multiTopLevelLargeImports.html]
+[test_multiModuleLargeImports.html]
+[test_asyncInlineModules.html]
+[test_scriptInsertedModule.html]
+[test_linkErrorInCommon1.html]
+[test_linkErrorInCommon2.html]
+[test_topLevelIntroType.html]
+[test_importIntroType.html]
+[test_dynamicImportErrorMessage.html]
diff --git a/dom/base/test/jsmodules/iframe_extractIntroType.html b/dom/base/test/jsmodules/iframe_extractIntroType.html
new file mode 100644
index 0000000000..26c58aea6d
--- /dev/null
+++ b/dom/base/test/jsmodules/iframe_extractIntroType.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ // Hook up the debugger statement to extract the calling script's
+ // introductionType and set it in a property on the parent global.
+ const {addSandboxedDebuggerToGlobal} = ChromeUtils.importESModule("resource://gre/modules/jsdebugger.sys.mjs");
+ addSandboxedDebuggerToGlobal(globalThis);
+ var dbg = new Debugger;
+ dbg.addDebuggee(parent);
+ dbg.onDebuggerStatement = function (frame) {
+ parent.introType = frame.script.source.introductionType;
+ }
+</script>
diff --git a/dom/base/test/jsmodules/importmaps/chrome.ini b/dom/base/test/jsmodules/importmaps/chrome.ini
new file mode 100644
index 0000000000..4fca7e97fa
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/chrome.ini
@@ -0,0 +1,29 @@
+[DEFAULT]
+support-files =
+ external_importMap.js
+ insert_a_base_element.js
+ module_simpleImportMap.js
+ module_simpleImportMap_dir.js
+ module_simpleImportMap_remap.js
+ module_simpleImportMap_remap_https.js
+ module_simpleExport.js
+ module_sortedImportMap.js
+ scope1/module_simpleExport.js
+ scope1/module_simpleImportMap.js
+ scope1/scope2/module_simpleExport.js
+ scope1/scope2/module_simpleImportMap.js
+prefs =
+ dom.importMaps.enabled=true
+
+[test_dynamic_import_reject_importMap.html]
+[test_externalImportMap.html]
+[test_import_meta_resolve_importMap.html]
+[test_inline_module_reject_importMap.html]
+[test_load_importMap_with_base.html]
+[test_load_importMap_with_base2.html]
+[test_module_script_reject_importMap.html]
+[test_parse_importMap_failed.html]
+[test_reject_multiple_importMaps.html]
+[test_simpleImportMap.html]
+[test_sortedImportMap.html]
+
diff --git a/dom/base/test/jsmodules/importmaps/external_importMap.js b/dom/base/test/jsmodules/importmaps/external_importMap.js
new file mode 100644
index 0000000000..e89d9f618f
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/external_importMap.js
@@ -0,0 +1,5 @@
+let imap = {
+ imports: {
+ foo: "./foo.js",
+ },
+};
diff --git a/dom/base/test/jsmodules/importmaps/insert_a_base_element.js b/dom/base/test/jsmodules/importmaps/insert_a_base_element.js
new file mode 100644
index 0000000000..435af97d1e
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/insert_a_base_element.js
@@ -0,0 +1,4 @@
+const el = document.createElement("base");
+el.href =
+ "chrome://mochitests/content/chrome/dom/base/test/jsmodules/importmaps/scope1/";
+document.currentScript.after(el);
diff --git a/dom/base/test/jsmodules/importmaps/module_simpleExport.js b/dom/base/test/jsmodules/importmaps/module_simpleExport.js
new file mode 100644
index 0000000000..9714d6d0ab
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/module_simpleExport.js
@@ -0,0 +1 @@
+export let x = 42;
diff --git a/dom/base/test/jsmodules/importmaps/module_simpleImportMap.js b/dom/base/test/jsmodules/importmaps/module_simpleImportMap.js
new file mode 100644
index 0000000000..153b84e6de
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/module_simpleImportMap.js
@@ -0,0 +1,2 @@
+import { x } from "simple";
+result = x;
diff --git a/dom/base/test/jsmodules/importmaps/module_simpleImportMap_dir.js b/dom/base/test/jsmodules/importmaps/module_simpleImportMap_dir.js
new file mode 100644
index 0000000000..554cc6a7bd
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/module_simpleImportMap_dir.js
@@ -0,0 +1,2 @@
+import { x } from "dir/module_simpleExport.js";
+result_dir = x + 1;
diff --git a/dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap.js b/dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap.js
new file mode 100644
index 0000000000..5ebaa30188
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap.js
@@ -0,0 +1,2 @@
+import { x } from "./module.js";
+result_remap = x + 2;
diff --git a/dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap_https.js b/dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap_https.js
new file mode 100644
index 0000000000..c047fd28c3
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/module_simpleImportMap_remap_https.js
@@ -0,0 +1,2 @@
+import { x } from "https://example.com/module.js";
+result_remap_https = x + 3;
diff --git a/dom/base/test/jsmodules/importmaps/module_sortedImportMap.js b/dom/base/test/jsmodules/importmaps/module_sortedImportMap.js
new file mode 100644
index 0000000000..41b2903097
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/module_sortedImportMap.js
@@ -0,0 +1,4 @@
+import { x } from "scope1/scope2/module_simpleExport.js";
+import { x as y } from "scope1/scope2/scope3/scope4/module_simpleExport.js";
+sorted_result = x;
+sorted_result2 = y;
diff --git a/dom/base/test/jsmodules/importmaps/moz.build b/dom/base/test/jsmodules/importmaps/moz.build
new file mode 100644
index 0000000000..1a7d5281ea
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_CHROME_MANIFESTS += ["chrome.ini"]
diff --git a/dom/base/test/jsmodules/importmaps/scope1/module_simpleExport.js b/dom/base/test/jsmodules/importmaps/scope1/module_simpleExport.js
new file mode 100644
index 0000000000..e6b0ed1c0c
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/scope1/module_simpleExport.js
@@ -0,0 +1 @@
+export let x = 84;
diff --git a/dom/base/test/jsmodules/importmaps/scope1/module_simpleImportMap.js b/dom/base/test/jsmodules/importmaps/scope1/module_simpleImportMap.js
new file mode 100644
index 0000000000..b1682e1900
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/scope1/module_simpleImportMap.js
@@ -0,0 +1,2 @@
+import { x } from "simple";
+result_scope1 = x;
diff --git a/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleExport.js b/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleExport.js
new file mode 100644
index 0000000000..ba2bbae16b
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleExport.js
@@ -0,0 +1 @@
+export let x = 126;
diff --git a/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleImportMap.js b/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleImportMap.js
new file mode 100644
index 0000000000..ecb38b7b21
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleImportMap.js
@@ -0,0 +1,2 @@
+import { x } from "simple";
+result_scope2 = x;
diff --git a/dom/base/test/jsmodules/importmaps/test_dynamic_import_reject_importMap.html b/dom/base/test/jsmodules/importmaps/test_dynamic_import_reject_importMap.html
new file mode 100644
index 0000000000..75471064f9
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_dynamic_import_reject_importMap.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test import map should be rejected.</title>
+</head>
+<body onload='testLoaded()'>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<!--There is a dynamic import before the import map tag, so the import map-->
+<!--cannot be accepted according to the spec.-->
+<!--And because the import map is rejected, so the module specifier-->
+<!--"./module_simpleExport.js" won't be remapped to-->
+<!--"./scope1/module_simpleExport.js".-->
+
+<script>
+ import("./module_simpleExport.js");
+</script>
+
+<script type="importmap" onerror='importMapError()'>
+{
+ "imports": {
+ "./module_simpleExport.js": "./scope1/module_simpleExport.js"
+ }
+}
+</script>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ let hasError = false;
+ function importMapError() {
+ hasError = true;
+ }
+
+ function testLoaded() {
+ import("./module_simpleExport.js").then((ns) => {
+ ok(ns.x == 42, 'Check simple imported value result: ' + ns.x);
+ ok(hasError, "onerror of the import map should be called.");
+ }).catch((e) => {
+ ok(false, "throws " + e);
+ }).then(() => {
+ SimpleTest.finish();
+ });
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_externalImportMap.html b/dom/base/test/jsmodules/importmaps/test_externalImportMap.html
new file mode 100644
index 0000000000..1345f61947
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_externalImportMap.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test an external import map</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+let gotMsg = false;
+let console = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+let listener = {
+ QueryInterface: ChromeUtils.generateQI(["nsIConsoleListener"]),
+ observe(msg) {
+ info("console message:" + msg);
+ ok(msg.logLevel == Ci.nsIConsoleMessage.warn, "log level should be 'warn'.");
+ // The message will be localized, so we just test the strings won't be
+ // localized.
+ ok(msg.message.match(/<script type='importmap'>.*src/),
+ "The error message should contain \"<script type='importmap'>\"");
+ console.unregisterListener(this);
+ gotMsg = true;
+ }
+};
+console.registerListener(listener);
+</script>
+
+<!--Import maps spec doesn't clearly define the format of an external import map script.-->
+<script src="external_importMap.js" type="importmap" onload="scriptLoaded()" onerror="scriptError()"></script>
+
+<script>
+function testLoaded() {
+ SimpleTest.waitForExplicitFinish();
+ ok(gotMsg, "Should have got the console warning.");
+ SimpleTest.finish();
+}
+
+function scriptLoaded() {
+ ok(false, "Loading external import map script should have failed.");
+}
+
+function scriptError() {
+ ok(true, "Loading external import map script failed.");
+}
+</script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/importmaps/test_import_meta_resolve_importMap.html b/dom/base/test/jsmodules/importmaps/test_import_meta_resolve_importMap.html
new file mode 100644
index 0000000000..df1bed2e56
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_import_meta_resolve_importMap.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test import.meta.resolve with import maps</title>
+</head>
+<body onload='testLoaded()'>
+
+<script type="importmap">
+{
+ "imports": {
+ "simple": "./module_simpleExport.js"
+ }
+}
+</script>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var hasThrown = false;
+ window.onerror = handleError;
+
+ function handleError(msg, url, line, col, error) {
+ ok(error instanceof TypeError, "Thrown error should be TypeError.");
+ hasThrown = true;
+ }
+</script>
+
+<script type="module">
+ ok(import.meta.resolve("simple") ==
+ "chrome://mochitests/content/chrome/dom/base/test/jsmodules/importmaps/module_simpleExport.js",
+ "calling import.meta.resolve with a specifier from import map.");
+ wasRun = true;
+</script>
+
+<script type="module">
+ // should throw a TypeError
+ import.meta.resolve("fail");
+</script>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(wasRun, "Check inline module has run.");
+ ok(hasThrown, "Check inline module has thrown.");
+ SimpleTest.finish();
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_inline_module_reject_importMap.html b/dom/base/test/jsmodules/importmaps/test_inline_module_reject_importMap.html
new file mode 100644
index 0000000000..2001cbcfb9
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_inline_module_reject_importMap.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test import map should be rejected.</title>
+</head>
+<body onload='testLoaded()'>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+let gotMsg = false;
+let console = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+let listener = {
+ QueryInterface: ChromeUtils.generateQI(["nsIConsoleListener"]),
+ observe(msg) {
+ info("console message:" + msg);
+ ok(msg.logLevel == Ci.nsIConsoleMessage.warn, "log level should be 'warn'.");
+ console.unregisterListener(this);
+ gotMsg = true;
+ }
+};
+console.registerListener(listener);
+</script>
+
+<!--There is an inline module before the import map tag, so the import map-->
+<!--cannot be accepted according to the spec.-->
+<!--And because the import map is rejected, so the module specifier-->
+<!--"./module_simpleExport.js" won't be remapped to-->
+<!--"./scope1/module_simpleExport.js".-->
+
+<script type="module">
+</script>
+
+<script type="importmap" onerror='importMapError()'>
+{
+ "imports": {
+ "./module_simpleExport.js": "./scope1/module_simpleExport.js"
+ }
+}
+</script>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ let hasError = false;
+ function importMapError() {
+ hasError = true;
+ }
+
+ function testLoaded() {
+ import("./module_simpleExport.js").then((ns) => {
+ ok(ns.x == 42, 'Check simple imported value result: ' + ns.x);
+ ok(hasError, "onerror of the import map should be called.");
+ ok(gotMsg, "Should have got the console warning.");
+ }).catch((e) => {
+ ok(false, "throws " + e);
+ }).then(() => {
+ SimpleTest.finish();
+ });
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_load_importMap_with_base.html b/dom/base/test/jsmodules/importmaps/test_load_importMap_with_base.html
new file mode 100644
index 0000000000..3139a60d37
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_load_importMap_with_base.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test a simple import map with a base element</title>
+</head>
+<body onload='testLoaded()'>
+
+<!-- This will change the baseURL of the document.-->
+<base href="chrome://mochitests/content/chrome/dom/base/test/jsmodules/importmaps/scope1/">
+
+<!--
+With the <base> element, the correct "module_simpleExport.js" should be mapped
+to "scope1/module_simpleExport.js", instead of "./module_simpleExport.js".
+-->
+
+<script type="importmap">
+{
+ "imports": {
+ "simple": "./module_simpleExport.js"
+ }
+}
+</script>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script type="module">
+ import { x } from "simple";
+ result2 = x;
+</script>
+
+<script type="module" src="module_simpleImportMap.js"></script>
+
+<script>
+ var result_scope1, result2;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(result_scope1 == 84, 'Check imported value result_scope1: ' + result_scope1);
+ ok(result2 == 84, 'Check imported value result2: ' + result2);
+
+ import("simple").then((ns) => {
+ ok(ns.x == 84, 'Check simple imported value result: ' + ns.x);
+ }).catch((e) => {
+ ok(false, "throws " + e);
+ }).then(() => {
+ SimpleTest.finish();
+ });
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_load_importMap_with_base2.html b/dom/base/test/jsmodules/importmaps/test_load_importMap_with_base2.html
new file mode 100644
index 0000000000..ed000512fd
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_load_importMap_with_base2.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test a simple import map with a script creates a base element</title>
+</head>
+<body onload='testLoaded()'>
+
+<!--This script will create a base element.-->
+<script src="insert_a_base_element.js"></script>
+
+<!--
+With the <base> element, the correct "module_simpleExport.js" should be mapped
+to "scope1/module_simpleExport.js", instead of "./module_simpleExport.js".
+-->
+
+<script type="importmap">
+{
+ "imports": {
+ "simple": "./module_simpleExport.js"
+ }
+}
+</script>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script type="module">
+ import { x } from "simple";
+ result2 = x;
+</script>
+
+<script type="module" src="module_simpleImportMap.js"></script>
+
+<script>
+ var result_scope1, result2;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(result_scope1 == 84, 'Check imported value result_scope1: ' + result_scope1);
+ ok(result2 == 84, 'Check imported value result2: ' + result2);
+
+ import("simple").then((ns) => {
+ ok(ns.x == 84, 'Check simple imported value result: ' + ns.x);
+ }).catch((e) => {
+ ok(false, "throws " + e);
+ }).then(() => {
+ SimpleTest.finish();
+ });
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_module_script_reject_importMap.html b/dom/base/test/jsmodules/importmaps/test_module_script_reject_importMap.html
new file mode 100644
index 0000000000..bc73a60fc9
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_module_script_reject_importMap.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test import map should be rejected.</title>
+</head>
+<body onload='testLoaded()'>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<!--There is a module load before the import map tag, so the import map cannot-->
+<!--be accepted according to the spec.-->
+<!--And because the import map is rejected, so the module specifier-->
+<!--"./module_simpleExport.js" won't be remapped to-->
+<!--"./scope1/module_simpleExport.js".-->
+
+<script src="./module_simpleExport.js" type="module">
+</script>
+
+<script type="importmap" onerror='importMapError()'>
+{
+ "imports": {
+ "./module_simpleExport.js": "./scope1/module_simpleExport.js"
+ }
+}
+</script>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ let hasError = false;
+ function importMapError() {
+ hasError = true;
+ }
+
+ function testLoaded() {
+ import("./module_simpleExport.js").then((ns) => {
+ ok(ns.x == 42, 'Check simple imported value result: ' + ns.x);
+ ok(hasError, "onerror of the import map should be called.");
+ }).catch((e) => {
+ ok(false, "throws " + e);
+ }).then(() => {
+ SimpleTest.finish();
+ });
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_parse_importMap_failed.html b/dom/base/test/jsmodules/importmaps/test_parse_importMap_failed.html
new file mode 100644
index 0000000000..b304acd943
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_parse_importMap_failed.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test the error message when parsing import maps failed</title>
+</head>
+<body onload='testLoaded()'>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+let gotMsg = false;
+window.onerror = function(event, src, lineno, colno, error) {
+ info("error: " + error.message);
+ ok(error instanceof SyntaxError, "error should be SyntaxError.");
+ ok(error.message.match(/import map/),
+ "error.message should contain 'import map'");
+ gotMsg = true;
+};
+</script>
+
+<!--
+An import map with invalid JSON format. A SyntaxError will be thrown when parsing
+the import map.
+ -->
+<script type="importmap" onerror='importMapError()'>
+{
+ "imports": {{
+ "foo": "./foo.js"
+ }
+}
+</script>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(gotMsg, "Should have thrown a SyntaxError.");
+ SimpleTest.finish();
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_reject_multiple_importMaps.html b/dom/base/test/jsmodules/importmaps/test_reject_multiple_importMaps.html
new file mode 100644
index 0000000000..cc41163101
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_reject_multiple_importMaps.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test the 2nd import map should be rejected.</title>
+</head>
+<body onload='testLoaded()'>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+let gotMsg = false;
+let console = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+let listener = {
+ QueryInterface: ChromeUtils.generateQI(["nsIConsoleListener"]),
+ observe(msg) {
+ info("console message:" + msg);
+ ok(msg.logLevel == Ci.nsIConsoleMessage.warn, "log level should be 'warn'.");
+ console.unregisterListener(this);
+ gotMsg = true;
+ }
+};
+console.registerListener(listener);
+</script>
+
+<script type="importmap" onerror='importMapError1()'>
+{
+ "imports": {
+ "./module_simpleExport.js": "./scope1/module_simpleExport.js"
+ }
+}
+</script>
+
+<!--The 2nd import map should be rejected.-->
+<script type="importmap" onerror='importMapError2()'>
+{
+ "imports": {
+ "./module_simpleExport.js": "./scope1/module_simpleExport.js"
+ }
+}
+</script>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ let hasError = false;
+ function importMapError1() {
+ ok(false, "The first import map should be accepted.");
+ }
+ function importMapError2() {
+ hasError = true;
+ }
+
+ function testLoaded() {
+ import("./module_simpleExport.js").then((ns) => {
+ ok(ns.x == 84, 'Check simple imported value result: ' + ns.x);
+ ok(hasError, "onerror of the import map should be called.");
+ ok(gotMsg, "Should have got the console warning.");
+ }).catch((e) => {
+ ok(false, "throws " + e);
+ }).then(() => {
+ SimpleTest.finish();
+ });
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/importmaps/test_simpleImportMap.html b/dom/base/test/jsmodules/importmaps/test_simpleImportMap.html
new file mode 100644
index 0000000000..6a46ff770e
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_simpleImportMap.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a simple import map</title>
+<script type="importmap">
+{
+ "imports": {
+ "simple": "./module_simpleExport.js",
+ "dir/": "/content/chrome/dom/base/test/jsmodules/importmaps/",
+ "./module.js": "/content/chrome/dom/base/test/jsmodules/importmaps/module_simpleExport.js",
+ "https://example.com/module.js": "./module_simpleExport.js"
+ },
+ "scopes": {
+ "chrome://mochitests/content/chrome/dom/base/test/jsmodules/importmaps/scope1/": {
+ "simple": "/content/chrome/dom/base/test/jsmodules/importmaps/scope1/module_simpleExport.js"
+ },
+ "chrome://mochitests/content/chrome/dom/base/test/jsmodules/importmaps/scope1/scope2/": {
+ "simple": "/content/chrome/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleExport.js"
+ }
+ }
+}
+</script>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+ var result, result_dir, result_remap, result_remap_https;
+ var result_scope1, result_scope2;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(result == 42, 'Check imported value result: ' + result);
+ ok(result_dir == 43, 'Check imported value result_dir: ' + result_dir);
+ ok(result_remap == 44, 'Check imported value result_remap: ' + result_remap);
+ ok(result_remap_https == 45,
+ 'Check imported value result_remap_https: ' + result_remap_https);
+ ok(result_scope1 == 84, 'Check imported value result_scope1: ' + result_scope1);
+ ok(result_scope2 == 126, 'Check imported value result_scope2: ' + result_scope2);
+
+ import("simple").then((ns) => {
+ ok(ns.x == 42, 'Check simple imported value result: ' + ns.x);
+ return import("dir/module_simpleExport.js");
+ }).then((ns) => {
+ ok(ns.x == 42, 'Check dir imported value result: ' + ns.x);
+ return import("./module.js");
+ }).then((ns) => {
+ ok(ns.x == 42, 'Check remap imported value result: ' + ns.x);
+ return import("https://example.com/module.js");
+ }).then((ns) => {
+ ok(ns.x == 42, 'Check remap https imported value result: ' + ns.x);
+ SimpleTest.finish();
+ });
+ }
+</script>
+<script type="module" src="module_simpleImportMap.js"></script>
+<script type="module" src="module_simpleImportMap_dir.js"></script>
+<script type="module" src="module_simpleImportMap_remap.js"></script>
+<script type="module" src="module_simpleImportMap_remap_https.js"></script>
+<script type="module" src="module_simpleImportMap_remap_https.js"></script>
+<script type="module" src="scope1/module_simpleImportMap.js"></script>
+<script type="module" src="scope1/scope2/module_simpleImportMap.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/importmaps/test_sortedImportMap.html b/dom/base/test/jsmodules/importmaps/test_sortedImportMap.html
new file mode 100644
index 0000000000..17e4049d1a
--- /dev/null
+++ b/dom/base/test/jsmodules/importmaps/test_sortedImportMap.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a sorted import map</title>
+
+<!--
+According to Import maps spec, the entries in "imports" and "scopes" need to be
+sorted. Key with longest prefix should be chosen. So "a/b/" should take
+precendence over "a/".
+This test is verifying that requirement.
+
+In "imports" below, "scope1/scope2/" and "scope1/scope2/scope3/scope4/" should
+be chosen over "scope1" and "scope1/scope2/scop3/" respectively.
+Also "scope1/scope2/" is listed _after_ "scope1/ and
+"scope1/scope2/scope3/scope4" is listed _before_ "scope1/scope2/scope3/" to make
+sure the map is sorted.
+
+For "scopes" below, the "scope1/" is listed before "scope1/scope2/" in
+test_simpleImportMap.html, here we reverse the order, for example, we list
+"scope1/" after "scope1/scope2/" in this test.
+
+See:
+https://html.spec.whatwg.org/multipage/webappapis.html#sorting-and-normalizing-a-module-specifier-map, Step 3.
+https://html.spec.whatwg.org/multipage/webappapis.html#sorting-and-normalizing-scopes, Step 3.
+-->
+
+<script type="importmap">
+{
+ "imports": {
+ "scope1/": "/content/chrome/dom/base/test/jsmodules/importmaps/",
+ "scope1/scope2/": "/content/chrome/dom/base/test/jsmodules/importmaps/scope1/scope2/",
+ "scope1/scope2/scope3/scope4/": "/content/chrome/dom/base/test/jsmodules/importmaps/scope1/scope2/",
+ "scope1/scope2/scope3/": "/content/chrome/dom/base/test/jsmodules/importmaps/"
+ },
+ "scopes": {
+ "chrome://mochitests/content/chrome/dom/base/test/jsmodules/importmaps/scope1/scope2/": {
+ "simple": "/content/chrome/dom/base/test/jsmodules/importmaps/scope1/scope2/module_simpleExport.js"
+ },
+ "chrome://mochitests/content/chrome/dom/base/test/jsmodules/importmaps/scope1/": {
+ "simple": "/content/chrome/dom/base/test/jsmodules/importmaps/scope1/module_simpleExport.js"
+ }
+ }
+}
+</script>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+ var sorted_result, sorted_result2;
+ var result_scope2;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(sorted_result == 126, 'Check imported value sorted_result: ' + sorted_result);
+ ok(sorted_result2 == 126, 'Check imported value sorted_result: ' + sorted_result2);
+ ok(result_scope2 == 126, 'Check imported value result_scope2: ' + result_scope2);
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_sortedImportMap.js"></script>
+<script type="module" src="scope1/scope2/module_simpleImportMap.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/module_badImport.js b/dom/base/test/jsmodules/module_badImport.js
new file mode 100644
index 0000000000..ab18249156
--- /dev/null
+++ b/dom/base/test/jsmodules/module_badImport.js
@@ -0,0 +1 @@
+import "invalid specifier";
diff --git a/dom/base/test/jsmodules/module_badSyntax.js b/dom/base/test/jsmodules/module_badSyntax.js
new file mode 100644
index 0000000000..744158108c
--- /dev/null
+++ b/dom/base/test/jsmodules/module_badSyntax.js
@@ -0,0 +1,3 @@
+// Module with a syntax error.
+some invalid js syntax;
+wasRun = true;
diff --git a/dom/base/test/jsmodules/module_cyclic1.js b/dom/base/test/jsmodules/module_cyclic1.js
new file mode 100644
index 0000000000..480efee0ae
--- /dev/null
+++ b/dom/base/test/jsmodules/module_cyclic1.js
@@ -0,0 +1,8 @@
+import { func2 } from "./module_cyclic2.js";
+
+export function func1(x, y) {
+ if (x <= 0) {
+ return y;
+ }
+ return func2(x - 1, y + "1");
+}
diff --git a/dom/base/test/jsmodules/module_cyclic2.js b/dom/base/test/jsmodules/module_cyclic2.js
new file mode 100644
index 0000000000..5f17afbd0a
--- /dev/null
+++ b/dom/base/test/jsmodules/module_cyclic2.js
@@ -0,0 +1,8 @@
+import { func3 } from "./module_cyclic3.js";
+
+export function func2(x, y) {
+ if (x <= 0) {
+ return y;
+ }
+ return func3(x - 1, y + "2");
+}
diff --git a/dom/base/test/jsmodules/module_cyclic3.js b/dom/base/test/jsmodules/module_cyclic3.js
new file mode 100644
index 0000000000..4b4c1e4ff6
--- /dev/null
+++ b/dom/base/test/jsmodules/module_cyclic3.js
@@ -0,0 +1,8 @@
+import { func1 } from "./module_cyclic1.js";
+
+export function func3(x, y) {
+ if (x <= 0) {
+ return y;
+ }
+ return func1(x - 1, y + "3");
+}
diff --git a/dom/base/test/jsmodules/module_extractIntroType.js b/dom/base/test/jsmodules/module_extractIntroType.js
new file mode 100644
index 0000000000..b2e1f1c6cf
--- /dev/null
+++ b/dom/base/test/jsmodules/module_extractIntroType.js
@@ -0,0 +1,5 @@
+// Extract the introductionType for this module in conjunction with
+// iframe_extractIntroType.html.
+extractIntroType = function () {
+ debugger;
+};
diff --git a/dom/base/test/jsmodules/module_large1.js b/dom/base/test/jsmodules/module_large1.js
new file mode 100644
index 0000000000..d6933d298d
--- /dev/null
+++ b/dom/base/test/jsmodules/module_large1.js
@@ -0,0 +1,78 @@
+/*
+ * Scripts larger than 5KB may be compiled off main thread. This is such a
+ * script.
+ *
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ */
+
+results.push(1);
diff --git a/dom/base/test/jsmodules/module_large2.js b/dom/base/test/jsmodules/module_large2.js
new file mode 100644
index 0000000000..e1b6da4c91
--- /dev/null
+++ b/dom/base/test/jsmodules/module_large2.js
@@ -0,0 +1,78 @@
+/*
+ * Scripts larger than 5KB may be compiled off main thread. This is such a
+ * script.
+ *
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ */
+
+results.push(2);
diff --git a/dom/base/test/jsmodules/module_large3.js b/dom/base/test/jsmodules/module_large3.js
new file mode 100644
index 0000000000..c966a8eb20
--- /dev/null
+++ b/dom/base/test/jsmodules/module_large3.js
@@ -0,0 +1,78 @@
+/*
+ * Scripts larger than 5KB may be compiled off main thread. This is such a
+ * script.
+ *
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ */
+
+results.push(3);
diff --git a/dom/base/test/jsmodules/module_missingImport.js b/dom/base/test/jsmodules/module_missingImport.js
new file mode 100644
index 0000000000..28cf608de8
--- /dev/null
+++ b/dom/base/test/jsmodules/module_missingImport.js
@@ -0,0 +1 @@
+import { missing } from "./module_simple1.js";
diff --git a/dom/base/test/jsmodules/module_multiImports.js b/dom/base/test/jsmodules/module_multiImports.js
new file mode 100644
index 0000000000..0587ac5ca0
--- /dev/null
+++ b/dom/base/test/jsmodules/module_multiImports.js
@@ -0,0 +1,4 @@
+import "./module_simple1.js";
+import "./module_simple2.js";
+import "./module_simple3.js";
+results.push(4);
diff --git a/dom/base/test/jsmodules/module_multiLargeImports.js b/dom/base/test/jsmodules/module_multiLargeImports.js
new file mode 100644
index 0000000000..ddc5792d0d
--- /dev/null
+++ b/dom/base/test/jsmodules/module_multiLargeImports.js
@@ -0,0 +1,4 @@
+import "./module_large1.js";
+import "./module_large2.js";
+import "./module_large3.js";
+results.push(4);
diff --git a/dom/base/test/jsmodules/module_setRan.js b/dom/base/test/jsmodules/module_setRan.js
new file mode 100644
index 0000000000..4804382fdd
--- /dev/null
+++ b/dom/base/test/jsmodules/module_setRan.js
@@ -0,0 +1,2 @@
+// Set a global flag to indicate that this module was executed.
+moduleRan = true;
diff --git a/dom/base/test/jsmodules/module_simple1.js b/dom/base/test/jsmodules/module_simple1.js
new file mode 100644
index 0000000000..7594ac699e
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simple1.js
@@ -0,0 +1 @@
+results.push(1);
diff --git a/dom/base/test/jsmodules/module_simple2.js b/dom/base/test/jsmodules/module_simple2.js
new file mode 100644
index 0000000000..f92a1c9d6e
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simple2.js
@@ -0,0 +1 @@
+results.push(2);
diff --git a/dom/base/test/jsmodules/module_simple3.js b/dom/base/test/jsmodules/module_simple3.js
new file mode 100644
index 0000000000..71979926e6
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simple3.js
@@ -0,0 +1 @@
+results.push(3);
diff --git a/dom/base/test/jsmodules/module_simpleExport.js b/dom/base/test/jsmodules/module_simpleExport.js
new file mode 100644
index 0000000000..9714d6d0ab
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simpleExport.js
@@ -0,0 +1 @@
+export let x = 42;
diff --git a/dom/base/test/jsmodules/module_simpleImport.js b/dom/base/test/jsmodules/module_simpleImport.js
new file mode 100644
index 0000000000..9e459fef7a
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simpleImport.js
@@ -0,0 +1,2 @@
+import { x } from "./module_simpleExport.js";
+result = x;
diff --git a/dom/base/test/jsmodules/module_testSyntax.js b/dom/base/test/jsmodules/module_testSyntax.js
new file mode 100644
index 0000000000..3d647ae0b4
--- /dev/null
+++ b/dom/base/test/jsmodules/module_testSyntax.js
@@ -0,0 +1,3 @@
+// Module that throws a syntax error if parsed as a script.
+export default 1;
+wasRun = true;
diff --git a/dom/base/test/jsmodules/moz.build b/dom/base/test/jsmodules/moz.build
new file mode 100644
index 0000000000..1a7d5281ea
--- /dev/null
+++ b/dom/base/test/jsmodules/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_CHROME_MANIFESTS += ["chrome.ini"]
diff --git a/dom/base/test/jsmodules/script_simple2.js b/dom/base/test/jsmodules/script_simple2.js
new file mode 100644
index 0000000000..f92a1c9d6e
--- /dev/null
+++ b/dom/base/test/jsmodules/script_simple2.js
@@ -0,0 +1 @@
+results.push(2);
diff --git a/dom/base/test/jsmodules/test_asyncInlineModules.html b/dom/base/test/jsmodules/test_asyncInlineModules.html
new file mode 100644
index 0000000000..188146e69c
--- /dev/null
+++ b/dom/base/test/jsmodules/test_asyncInlineModules.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test async inline modules</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results.sort(), [1, 2, 3]), 'Check modules imported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" async>
+ results.push(1);
+</script>
+<script type="module" async>
+ import "./module_simple2.js";
+</script>
+<script type="module" async>
+ results.push(3);
+</script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_cyclicImport.html b/dom/base/test/jsmodules/test_cyclicImport.html
new file mode 100644
index 0000000000..d316a140d4
--- /dev/null
+++ b/dom/base/test/jsmodules/test_cyclicImport.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test cyclic module imports</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var result;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ SimpleTest.finish();
+ }
+</script>
+<script type="module">
+ import { func1 } from "./module_cyclic1.js";
+ ok(func1(5, "") == "12312");
+</script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_dynamicImportErrorMessage.html b/dom/base/test/jsmodules/test_dynamicImportErrorMessage.html
new file mode 100644
index 0000000000..f5552d5a6b
--- /dev/null
+++ b/dom/base/test/jsmodules/test_dynamicImportErrorMessage.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test the error message from import()</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ async function testLoaded() {
+ await import("./404.js").catch((error) => {
+ ok(error instanceof TypeError, "Should be a TypeError.");
+ ok(error.message.match(/404.js/), "Should have the filename.");
+ SimpleTest.finish();
+ });
+ }
+</script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_importIntroType.html b/dom/base/test/jsmodules/test_importIntroType.html
new file mode 100644
index 0000000000..67c08bb5d7
--- /dev/null
+++ b/dom/base/test/jsmodules/test_importIntroType.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test introduction type of an imported module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var introType;
+ var extractIntroType;
+
+ info('start');
+ SimpleTest.waitForExplicitFinish();
+
+ function testIntroductionType() {
+ extractIntroType();
+ ok(introType == "importedModule", 'Check introduction type');
+ SimpleTest.finish();
+ }
+</script>
+<iframe src="iframe_extractIntroType.html"></iframe>
+<script type="module">
+import "./module_extractIntroType.js";
+</script>
+<body onload='testIntroductionType()'></body>
diff --git a/dom/base/test/jsmodules/test_importNotFound.html b/dom/base/test/jsmodules/test_importNotFound.html
new file mode 100644
index 0000000000..fc624b6b68
--- /dev/null
+++ b/dom/base/test/jsmodules/test_importNotFound.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test what happens when a module import is not found</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var errorCount = 0;
+ var eventCount = 0;
+
+ SimpleTest.waitForExplicitFinish();
+
+ window.onerror = function(message, url, line, column, error) {
+ errorCount++;
+ }
+
+ function testError() {
+ ok(!wasRun, 'Check script was not run');
+ ok(eventCount == 1, 'Check that an error event was fired');
+ ok(errorCount == 0, 'Check that no error was reported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" onerror="eventCount++">
+import "./nonExistentModule.js";
+wasRun = true;
+</script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_importResolveFailed.html b/dom/base/test/jsmodules/test_importResolveFailed.html
new file mode 100644
index 0000000000..559de77dcd
--- /dev/null
+++ b/dom/base/test/jsmodules/test_importResolveFailed.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test error thrown when an import cannot be resolved</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var hadTypeError = false;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ hadTypeError = error instanceof TypeError;
+ }
+
+ function testError() {
+ ok(hadTypeError, 'Check that a TypeError was thrown');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_badImport.js"></script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_import_meta_resolve.html b/dom/base/test/jsmodules/test_import_meta_resolve.html
new file mode 100644
index 0000000000..66eedc95bc
--- /dev/null
+++ b/dom/base/test/jsmodules/test_import_meta_resolve.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<head>
+ <meta charset=utf-8>
+ <title>Test import.meta.resolve</title>
+</head>
+<body onload='testLoaded()'>
+
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ function assertThrowsTypeError(fn, msg) {
+ let hasThrown = false;
+ try {
+ fn();
+ } catch (error) {
+ hasThrown = true;
+ ok(error instanceof TypeError, "Thrown error should be TypeError.");
+ }
+ ok(hasThrown, msg);
+ }
+
+ function testLoaded() {
+ SimpleTest.finish();
+ }
+</script>
+
+<script type="module">
+ is(typeof import.meta.resolve, "function", "resolve should be a function.");
+ is(import.meta.resolve.name, "resolve", "resolve.name should be 'resolve'.");
+ is(import.meta.resolve.length, 1, "resolve.length should be 1.");
+ is(Object.getPrototypeOf(import.meta.resolve), Function.prototype,
+ "prototype of resolve should be Function.prototype.");
+</script>
+
+<script type="module">
+ is(import.meta.resolve("http://example.com/"), "http://example.com/",
+ "resolve specifiers with absolute path.");
+</script>
+
+<script type="module">
+ is(import.meta.resolve("./x"), (new URL("./x", import.meta.url)).href,
+ "resolve specifiers with relative path.");
+</script>
+
+<script type="module">
+ assertThrowsTypeError(() => new import.meta.resolve("./x"),
+ "import.meta.resolve is not a constructor.");
+</script>
+
+<script type="module">
+ // Fails to resolve the specifier should throw a TypeError.
+ assertThrowsTypeError(() => import.meta.resolve("failed"),
+ "import.meta.resolve should throw if fails to resolve");
+</script>
+
+<script type="module">
+ for (const name of Reflect.ownKeys(import.meta)) {
+ const desc = Object.getOwnPropertyDescriptor(import.meta, name);
+ is(desc.writable, true, name + ".writable should be true.");
+ is(desc.enumerable, true, name + ".enumerable should be true.");
+ is(desc.configurable, true, name + ".configurable should be true.");
+ }
+</script>
+</body>
diff --git a/dom/base/test/jsmodules/test_importedModuleMemoization.html b/dom/base/test/jsmodules/test_importedModuleMemoization.html
new file mode 100644
index 0000000000..37cb26752d
--- /dev/null
+++ b/dom/base/test/jsmodules/test_importedModuleMemoization.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test imported modules are momoized and only loaded once</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results, [1, 2, 3, 4]), 'Check modules only evaluated once');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_multiImports.js"></script>
+<script type="module" src="module_multiImports.js"></script>
+<script type="module" src="module_multiImports.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_linkErrorInCommon1.html b/dom/base/test/jsmodules/test_linkErrorInCommon1.html
new file mode 100644
index 0000000000..436493c75e
--- /dev/null
+++ b/dom/base/test/jsmodules/test_linkErrorInCommon1.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test handling of a link error in a common module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var runCount = 0;
+ var hadSyntaxError = false;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ if (error instanceof SyntaxError) {
+ hadSyntaxError = true;
+ }
+ }
+
+ function testError() {
+ ok(runCount == 0, 'Check no modules were executed');
+ ok(hadSyntaxError, 'Check that an error was reported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module">
+ import { missing } from "./module_simple1.js";
+ runCount++;
+</script>
+<script type="module">
+ import { missing } from "./module_simple1.js";
+ runCount++;
+</script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_linkErrorInCommon2.html b/dom/base/test/jsmodules/test_linkErrorInCommon2.html
new file mode 100644
index 0000000000..a882ec0992
--- /dev/null
+++ b/dom/base/test/jsmodules/test_linkErrorInCommon2.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test handling of a link error in a common module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var runCount = 0;
+ var hadSyntaxError = false;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ if (error instanceof SyntaxError) {
+ hadSyntaxError = true;
+ }
+ }
+
+ function testError() {
+ ok(runCount == 0, 'Check no modules were executed');
+ ok(hadSyntaxError, 'Check that an error was reported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module">
+ import "./module_missingImport.js";
+ runCount++;
+</script>
+<script type="module">
+ import "./module_missingImport.js";
+ runCount++;
+</script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_moduleNotFound.html b/dom/base/test/jsmodules/test_moduleNotFound.html
new file mode 100644
index 0000000000..f5e7c37364
--- /dev/null
+++ b/dom/base/test/jsmodules/test_moduleNotFound.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test what happens when a top-level module is not found</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var errorCount = 0;
+ var eventCount = 0;
+
+ SimpleTest.waitForExplicitFinish();
+
+ window.onerror = function(message, url, line, column, error) {
+ errorCount++;
+ }
+
+ function testError() {
+ ok(eventCount == 1, 'Check that an error event was fired');
+ ok(errorCount == 0, 'Check that no error was reported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="./nonExistentModule.js" onerror="eventCount++">
+</script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_moduleParsedAsModule.html b/dom/base/test/jsmodules/test_moduleParsedAsModule.html
new file mode 100644
index 0000000000..2cd4abbd57
--- /dev/null
+++ b/dom/base/test/jsmodules/test_moduleParsedAsModule.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test module script parsed as module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var hadSyntaxError = false;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ hadSyntaxError = error instanceof SyntaxError;
+ }
+
+ function testError() {
+ ok(wasRun, 'Check module was run');
+ ok(!hadSyntaxError, 'Check that no SyntaxError was thrown');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_testSyntax.js"></script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_moduleScriptsRun.html b/dom/base/test/jsmodules/test_moduleScriptsRun.html
new file mode 100644
index 0000000000..908f7ff46a
--- /dev/null
+++ b/dom/base/test/jsmodules/test_moduleScriptsRun.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test script elements with type="module" are run for chrome HTML</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var inlineModuleRan = false;
+ var moduleRan = false;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(moduleRan, 'Check module script was run');
+ ok(inlineModuleRan, 'Check inline module script was run');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_setRan.js"></script>
+<script type="module">inlineModuleRan = true;</script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_multiAsyncImports.html b/dom/base/test/jsmodules/test_multiAsyncImports.html
new file mode 100644
index 0000000000..dc318851c8
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiAsyncImports.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a loading multiple modules with the async attribute from top level</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results.sort(), [1, 2, 3]), 'Check modules imported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_simple1.js" async></script>
+<script type="module" src="module_simple2.js" async></script>
+<script type="module" src="module_simple3.js" async></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_multiModuleImports.html b/dom/base/test/jsmodules/test_multiModuleImports.html
new file mode 100644
index 0000000000..003f7e6754
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiModuleImports.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a importing multiple modules from a module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results, [1, 2, 3, 4]), 'Check modules imported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_multiImports.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_multiModuleLargeImports.html b/dom/base/test/jsmodules/test_multiModuleLargeImports.html
new file mode 100644
index 0000000000..f590bae449
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiModuleLargeImports.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test importing multiple large modules which may be compiled off main thread from a module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results, [1, 2, 3, 4]), 'Check modules imported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_multiLargeImports.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_multiTopLevelImports.html b/dom/base/test/jsmodules/test_multiTopLevelImports.html
new file mode 100644
index 0000000000..7cfe600959
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiTopLevelImports.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test importing multiple modules from top level</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results, [1, 2, 3]), 'Check modules imported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_simple1.js"></script>
+<script type="module" src="module_simple2.js"></script>
+<script type="module" src="module_simple3.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_multiTopLevelLargeImports.html b/dom/base/test/jsmodules/test_multiTopLevelLargeImports.html
new file mode 100644
index 0000000000..8deee5479e
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiTopLevelLargeImports.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a importing large modules which may be compiled off main thread</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results, [1, 2, 3]), 'Check modules imported');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_large1.js"></script>
+<script type="module" src="module_simple2.js"></script>
+<script type="module" src="module_large3.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_scriptInsertedModule.html b/dom/base/test/jsmodules/test_scriptInsertedModule.html
new file mode 100644
index 0000000000..3f00ab9684
--- /dev/null
+++ b/dom/base/test/jsmodules/test_scriptInsertedModule.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a script-inserted module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var result;
+
+ let script = document.createElement("script");
+ script.type = "module";
+ script.src = "./module_simpleImport.js";
+ document.head.appendChild(script);
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(result == 42);
+ SimpleTest.finish();
+ }
+</script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_scriptModuleOrder.html b/dom/base/test/jsmodules/test_scriptModuleOrder.html
new file mode 100644
index 0000000000..bd8a4dcebe
--- /dev/null
+++ b/dom/base/test/jsmodules/test_scriptModuleOrder.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test execution order of deferred scripts and modules </title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results, [1, 2, 3]), 'Check execution order');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_simple1.js"></script>
+<script defer src="script_simple2.js"></script>
+<script type="module" src="module_simple3.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_scriptNotParsedAsModule.html b/dom/base/test/jsmodules/test_scriptNotParsedAsModule.html
new file mode 100644
index 0000000000..ba09503503
--- /dev/null
+++ b/dom/base/test/jsmodules/test_scriptNotParsedAsModule.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test classic script not parsed as module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var hadSyntaxError = false;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ hadSyntaxError = error instanceof SyntaxError;
+ }
+
+ function testError() {
+ ok(!wasRun, 'Check script was not run');
+ ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
+ SimpleTest.finish();
+ }
+</script>
+<script src="module_testSyntax.js"></script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_simpleImport.html b/dom/base/test/jsmodules/test_simpleImport.html
new file mode 100644
index 0000000000..3c1af3f5b6
--- /dev/null
+++ b/dom/base/test/jsmodules/test_simpleImport.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a simple module import</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var result;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(result == 42, 'Check imported value');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_simpleImport.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_syntaxError.html b/dom/base/test/jsmodules/test_syntaxError.html
new file mode 100644
index 0000000000..180c5aa445
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxError.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing a module are reported</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var errorCount = 0;
+ var syntaxErrorCount = 0;
+ var eventCount = 0;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ errorCount++;
+ if (error instanceof SyntaxError) {
+ syntaxErrorCount++;
+ }
+ }
+
+ function testError() {
+ ok(!wasRun, 'Check script was not run');
+ ok(errorCount == 1, 'Check that an error was reported');
+ ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
+ ok(eventCount == 0, 'Check that no error event was fired');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_badSyntax.js" onerror="eventCount++"></script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_syntaxErrorAsync.html b/dom/base/test/jsmodules/test_syntaxErrorAsync.html
new file mode 100644
index 0000000000..64d8e6a21c
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxErrorAsync.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing an async module are reported</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var errorCount = 0;
+ var syntaxErrorCount = 0;
+ var eventCount = 0;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ errorCount++;
+ if (error instanceof SyntaxError) {
+ syntaxErrorCount++;
+ }
+ }
+
+ function testError() {
+ ok(!wasRun, 'Check script was not run');
+ ok(errorCount == 1, 'Check that an error was reported');
+ ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
+ ok(eventCount == 0, 'Check that no error event was fired');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_badSyntax.js" async onerror="eventCount++"></script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_syntaxErrorInline.html b/dom/base/test/jsmodules/test_syntaxErrorInline.html
new file mode 100644
index 0000000000..4960f5358a
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxErrorInline.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing an inline module are reported</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var errorCount = 0;
+ var syntaxErrorCount = 0;
+ var eventCount = 0;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ errorCount++;
+ if (error instanceof SyntaxError) {
+ syntaxErrorCount++;
+ }
+ }
+
+ function testError() {
+ ok(!wasRun, 'Check script was not run');
+ ok(errorCount == 1, 'Check that an error was reported');
+ ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
+ ok(eventCount == 0, 'Check that no error event was fired');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" onerror="eventCount++">
+// Module with a syntax error.
+some invalid js syntax;
+wasRun = true;
+</script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html b/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html
new file mode 100644
index 0000000000..39b8a7354d
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing an inline async module are reported</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var wasRun = false;
+ var errorCount = 0;
+ var syntaxErrorCount = 0;
+ var eventCount = 0;
+
+ SimpleTest.waitForExplicitFinish();
+ window.onerror = handleError;
+
+ function handleError(message, url, line, column, error) {
+ errorCount++;
+ if (error instanceof SyntaxError) {
+ syntaxErrorCount++;
+ }
+ }
+
+ function testError() {
+ ok(!wasRun, 'Check script was not run');
+ ok(errorCount == 1, 'Check that an error was reported');
+ ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
+ ok(eventCount == 0, 'Check that no error event was fired');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" async onerror="eventCount++">
+// Module with a syntax error.
+some invalid js syntax;
+wasRun = true;
+</script>
+<body onload='testError()'></body>
diff --git a/dom/base/test/jsmodules/test_topLevelIntroType.html b/dom/base/test/jsmodules/test_topLevelIntroType.html
new file mode 100644
index 0000000000..2c9c91b5bd
--- /dev/null
+++ b/dom/base/test/jsmodules/test_topLevelIntroType.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test introduction type of a top-level module</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var introType;
+ var extractIntroType;
+
+ info('start');
+ SimpleTest.waitForExplicitFinish();
+
+ function testIntroductionType() {
+ extractIntroType();
+ ok(introType == "srcScript", 'Check introduction type');
+ SimpleTest.finish();
+ }
+</script>
+<iframe src="iframe_extractIntroType.html"></iframe>
+<script type="module" src="module_extractIntroType.js">
+</script>
+<body onload='testIntroductionType()'></body>
diff --git a/dom/base/test/jsmodules/test_toplevelModuleMemoization.html b/dom/base/test/jsmodules/test_toplevelModuleMemoization.html
new file mode 100644
index 0000000000..ed4dee6f8b
--- /dev/null
+++ b/dom/base/test/jsmodules/test_toplevelModuleMemoization.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test toplevel modules are momoized and only loaded once</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var results = [];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function arrayEquals(a, b) {
+ if (a.length != b.length) {
+ return false;
+ }
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function testLoaded() {
+ ok(arrayEquals(results, [1]), 'Check execution order');
+ SimpleTest.finish();
+ }
+</script>
+<script type="module" src="module_simple1.js"></script>
+<script type="module" src="module_simple1.js"></script>
+<script type="module" src="module_simple1.js"></script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/jsmodules/test_typeAttrCaseInsensitive.html b/dom/base/test/jsmodules/test_typeAttrCaseInsensitive.html
new file mode 100644
index 0000000000..47ebc90dd6
--- /dev/null
+++ b/dom/base/test/jsmodules/test_typeAttrCaseInsensitive.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test script element's type attribute comparision is case-insensitive</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+ var inlineModuleRan = false;
+ var moduleRan = false;
+
+ SimpleTest.waitForExplicitFinish();
+
+ function testLoaded() {
+ ok(moduleRan, 'Check module script was run');
+ ok(inlineModuleRan, 'Check inline module script was run');
+ SimpleTest.finish();
+ }
+</script>
+<script type="MODULE" src="module_setRan.js"></script>
+<script type="mOdUlE">inlineModuleRan = true;</script>
+<body onload='testLoaded()'></body>
diff --git a/dom/base/test/meta_viewport/mochitest.ini b/dom/base/test/meta_viewport/mochitest.ini
new file mode 100644
index 0000000000..cfe63cc999
--- /dev/null
+++ b/dom/base/test/meta_viewport/mochitest.ini
@@ -0,0 +1,54 @@
+[DEFAULT]
+support-files =
+ viewport_helpers.js
+
+[test_meta_viewport0.html]
+[test_meta_viewport1.html]
+[test_meta_viewport2.html]
+[test_meta_viewport3.html]
+[test_meta_viewport4.html]
+[test_meta_viewport5.html]
+[test_meta_viewport6.html]
+[test_meta_viewport7.html]
+[test_meta_viewport8.html]
+[test_meta_viewport_auto_size_by_device_height.html]
+[test_meta_viewport_auto_size_by_device_width.html]
+[test_meta_viewport_auto_size_by_fixed_height_and_initial_scale_1.html]
+[test_meta_viewport_auto_size_by_fixed_width_and_device_height.html]
+[test_meta_viewport_auto_size_by_fixed_width_and_initial_scale_1.html]
+[test_meta_viewport_auto_size_by_initial_scale_0_5.html]
+[test_meta_viewport_auto_size_by_initial_scale_1.html]
+[test_meta_viewport_auto_size_by_invalid_width.html]
+[test_meta_viewport_auto_size_by_invalid_width_and_fixed_height.html]
+[test_meta_viewport_change_content_among_multiple.html]
+[test_meta_viewport_change_name.html]
+[test_meta_viewport_change_name_among_multiple.html]
+[test_meta_viewport_device_width.html]
+[test_meta_viewport_device_width_with_initial_scale_0_5.html]
+[test_meta_viewport_device_width_with_initial_scale_2.html]
+[test_meta_viewport_fit.html]
+[test_meta_viewport_fit_multiple.html]
+[test_meta_viewport_fixed_width_and_zero_display_width.html]
+[test_meta_viewport_initial_scale_0_5.html]
+[test_meta_viewport_initial_scale_2.html]
+[test_meta_viewport_insert_before_existing_tag.html]
+[test_meta_viewport_maximum_scale_0.html]
+[test_meta_viewport_maximum_scale_0_5.html]
+[test_meta_viewport_maximum_scale_2.html]
+[test_meta_viewport_multiple_tags.html]
+[test_meta_viewport_negative_width_and_negative_height.html]
+[test_meta_viewport_negative_width_and_no_height.html]
+[test_meta_viewport_negative_width_and_valid_height.html]
+[test_meta_viewport_valid_width_and_negative_height.html]
+[test_meta_viewport_valid_width_and_no_height.html]
+[test_meta_viewport_no_width_and_negative_height.html]
+[test_meta_viewport_no_width_and_valid_height.html]
+[test_meta_viewport_remove_node.html]
+[test_meta_viewport_remove_node_from_multiple.html]
+[test_meta_viewport_replace_content.html]
+[test_meta_viewport_tiny_display_size.html]
+[test_meta_viewport_initial_scale_with_trailing_characters.html]
+[test_meta_viewport_width_with_trailing_characters.html]
+[test_meta_viewport_empty_content_and_valid_content_tags.html]
+[test_meta_viewport_no_content_and_valid_content_tags.html]
+[test_meta_viewport_removing_content_attribute.html]
diff --git a/dom/base/test/meta_viewport/moz.build b/dom/base/test/meta_viewport/moz.build
new file mode 100644
index 0000000000..60b508c774
--- /dev/null
+++ b/dom/base/test/meta_viewport/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += [
+ "mochitest.ini",
+]
diff --git a/dom/base/test/meta_viewport/test_meta_viewport0.html b/dom/base/test/meta_viewport/test_meta_viewport0.html
new file mode 100644
index 0000000000..8fef72c578
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport0.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>No &lt;meta name="viewport"&gt; tag</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ fuzzeq(info.defaultZoom, 0.25, "initial scale is clamped to the default mimumim scale");
+ fuzzeq(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 980, "width is the default width");
+ is(info.height, 588, "height is proportional to displayHeight");
+ is(info.autoSize, false, "autoSize is disabled by default");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ info = getViewportInfo(490, 600);
+ is(info.width, 980, "width is still the default width");
+ is(info.height, 1200, "height is proportional to the new displayHeight");
+ });
+
+ add_task(async function test2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.5));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 980, "width is still the default width");
+ is(info.height, 588, "height is still proportional to displayHeight");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport1.html b/dom/base/test/meta_viewport/test_meta_viewport1.html
new file mode 100644
index 0000000000..66dd02461e
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport1.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width, initial-scale=1</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 100%");
+ is(info.width, 800, "width is the same as the displayWidth");
+ is(info.height, 480, "height is the same as the displayHeight");
+ is(info.autoSize, true, "width=device-width enables autoSize");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ info = getViewportInfo(900, 600);
+ is(info.width, 900, "changing the displayWidth changes the width");
+ is(info.height, 600, "changing the displayHeight changes the height");
+ });
+
+ add_task(async function test2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.5));
+
+ let info = getViewportInfo(900, 600);
+ is(info.defaultZoom, 1.5, "initial zoom is 150%");
+ is(info.width, 600, "width equals displayWidth/1.5");
+ is(info.height, 400, "height equals displayHeight/1.5");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport2.html b/dom/base/test/meta_viewport/test_meta_viewport2.html
new file mode 100644
index 0000000000..e0f45813be
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport2.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 100%");
+ is(info.width, 800, "width is the same as the displayWidth");
+ is(info.height, 480, "height is the same as the displayHeight");
+ is(info.autoSize, true, "width=device-width enables autoSize");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ info = getViewportInfo(900, 600);
+ is(info.width, 900, "changing the displayWidth changes the width");
+ is(info.height, 600, "changing the displayHeight changes the height");
+ });
+
+ add_task(async function test2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.5));
+
+ let info = getViewportInfo(900, 600);
+ is(info.defaultZoom, 1.5, "initial zoom is 150%");
+ is(info.width, 600, "width equals displayWidth/1.5");
+ is(info.height, 400, "height equals displayHeight/1.5");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport3.html b/dom/base/test/meta_viewport/test_meta_viewport3.html
new file mode 100644
index 0000000000..32464bd126
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport3.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=320">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=320</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 80);
+ is(info.defaultZoom, 2.5, "initial zoom fits the displayWidth");
+ is(info.width, 320, "width is set explicitly");
+ is(info.height, 40, "height is at the absolute minimum");
+ is(info.autoSize, false, "width=device-width enables autoSize");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ info = getViewportInfo(480, 800);
+ is(info.defaultZoom, 1.5, "initial zoom fits the new displayWidth");
+ is(info.width, 320, "explicit width is unchanged");
+ is(info.height, 533, "height changes proportional to displayHeight");
+ });
+
+ add_task(async function test2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.5));
+
+ // With an explicit width in CSS px, the scaleRatio has no effect.
+ let info = getViewportInfo(800, 80);
+ is(info.defaultZoom, 2.5, "initial zoom still fits the displayWidth");
+ is(info.width, 320, "width is still set explicitly");
+ is(info.height, 40, "height is still minimum height");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport4.html b/dom/base/test/meta_viewport/test_meta_viewport4.html
new file mode 100644
index 0000000000..bc7f7ada55
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport4.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>initial-scale=1.0, user-scalable=no</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is set explicitly");
+ is(info.width, 800, "width fits the initial zoom level");
+ is(info.height, 480, "height fits the initial zoom level");
+ is(info.autoSize, true, "initial-scale=1 enables autoSize");
+ is(info.allowZoom, false, "zooming is explicitly disabled");
+
+ info = getViewportInfo(480, 800);
+ is(info.defaultZoom, 1, "initial zoom is still set explicitly");
+ is(info.width, 480, "width changes to match the displayWidth");
+ is(info.height, 800, "height changes to match the displayHeight");
+ });
+
+ add_task(async function test2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.5));
+
+ let info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1.5, "initial zoom is adjusted for device pixel ratio");
+ is(info.width, 533, "width fits the initial zoom");
+ is(info.height, 320, "height fits the initial zoom");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport5.html b/dom/base/test/meta_viewport/test_meta_viewport5.html
new file mode 100644
index 0000000000..938cc052ee
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport5.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="user-scalable=NO">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>user-scalable=NO</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.allowZoom, true, "user-scalable values are case-sensitive; 'NO' is not valid");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport6.html b/dom/base/test/meta_viewport/test_meta_viewport6.html
new file mode 100644
index 0000000000..e3ca1b72aa
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport6.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=2000, minimum-scale=0.75">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=2000, minimum-scale=0.75</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.minZoom, 0.75, "minumum scale is set explicitly");
+ is(info.defaultZoom, 0.75, "initial scale is bounded by the minimum scale");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 2000, "width is set explicitly");
+ is(info.height, 1200, "height is proportional to displayHeight");
+ is(info.autoSize, false, "autoSize is disabled by default");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ info = getViewportInfo(2000, 1000);
+ is(info.minZoom, 0.75, "minumum scale is still set explicitly");
+ is(info.defaultZoom, 1, "initial scale fits the width");
+ is(info.width, 2000, "width is set explicitly");
+ is(info.height, 1000, "height is proportional to the new displayHeight");
+ });
+
+ add_task(async function test2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.5));
+
+ let info = getViewportInfo(800, 480);
+ is(info.minZoom, 1.125, "minumum scale is converted to device pixel scale");
+ is(info.defaultZoom, 1.125, "initial scale is bounded by the minimum scale");
+ is(info.maxZoom, 15, "maximum scale defaults to the absolute maximum");
+ is(info.width, 2000, "width is still set explicitly");
+ is(info.height, 1200, "height is still proportional to displayHeight");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport7.html b/dom/base/test/meta_viewport/test_meta_viewport7.html
new file mode 100644
index 0000000000..1f40c27109
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport7.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=320">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>Dynamic viewport updates</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ updateViewport("width=device-width");
+ let info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 100%");
+ is(info.width, 800, "width is the same as the displayWidth");
+ is(info.height, 480, "height is the same as the displayHeight");
+ is(info.autoSize, true, "width=device-width enables autoSize");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ info = getViewportInfo(900, 600);
+ is(info.width, 900, "changing the displayWidth changes the width");
+ is(info.height, 600, "changing the displayHeight changes the height");
+ });
+
+ add_task(async function test2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ updateViewport("width=320");
+ let info = getViewportInfo(800, 80);
+ is(info.defaultZoom, 2.5, "initial zoom fits the displayWidth");
+ is(info.width, 320, "width is set explicitly");
+ is(info.height, 40, "height is at the absolute minimum");
+ is(info.autoSize, false, "width=device-width enables autoSize");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ info = getViewportInfo(480, 800);
+ is(info.defaultZoom, 1.5, "initial zoom fits the new displayWidth");
+ is(info.width, 320, "explicit width is unchanged");
+ is(info.height, 533, "height changes proportional to displayHeight");
+ });
+
+ add_task(async function test3() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ updateViewport("user-scalable=no");
+ let info = getViewportInfo(800, 480);
+ is(info.allowZoom, false, "zooming is explicitly disabled");
+ });
+
+ add_task(async function test4() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ updateViewport("user-scalable=yes");
+ let info = getViewportInfo(800, 480);
+ is(info.allowZoom, true, "zooming is explicitly allowed");
+ });
+
+ function updateViewport(content) {
+ let meta = document.querySelector("meta[name=viewport]");
+ meta.content = content;
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport8.html b/dom/base/test/meta_viewport/test_meta_viewport8.html
new file mode 100644
index 0000000000..4c711c9cc6
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport8.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="initial-scale=0.01">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>minimum-scale=0.01</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.defaultZoom, 0.25, "initial scale is bounded by the minimum scale");
+ is(info.width, 3200, "width is scaled correctly by zoom level");
+ is(info.height, 1920, "height is scaled correctly by zoom level");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_height.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_height.html
new file mode 100644
index 0000000000..1b6c35a602
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_height.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>device-height enables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="height=device-height">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>height=device-height</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function device_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(info.autoSize, "device-height should enable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_width.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_width.html
new file mode 100644
index 0000000000..fb91f2e50c
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_device_width.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>device-width enables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function device_width() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(info.autoSize, "device-width should enable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_height_and_initial_scale_1.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_height_and_initial_scale_1.html
new file mode 100644
index 0000000000..83346f4924
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_height_and_initial_scale_1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>initial-scale=1 with fixed height enable autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="height=400, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>height=400, initial-scale=1</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function fixed_height_and_initial_scale_1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(info.autoSize,
+ "initial-scale=1 with fixed height should enable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_device_height.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_device_height.html
new file mode 100644
index 0000000000..e570f80644
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_device_height.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Fixed width and device-height disables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400,height=device-height">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=400, height=device-height</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function fixed_width_and_device_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(!info.autoSize,
+ "Fixed width should disable autoSize even if height is device-height");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_initial_scale_1.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_initial_scale_1.html
new file mode 100644
index 0000000000..4453b4c959
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_fixed_width_and_initial_scale_1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>initial-scale=1 with fixed width disables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=400, initial-scale=1</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function fixed_width_and_initial_scale_1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(!info.autoSize,
+ "initial-scale=1 with fixed width should disable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_0_5.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_0_5.html
new file mode 100644
index 0000000000..ff12b22454
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_0_5.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>initial-scale!=1 without width disables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="initial-scale=0.5">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>initial-scale!=1</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function initial_scale_0_5() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(!info.autoSize,
+ "initial-scale!=1 without width should disable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_1.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_1.html
new file mode 100644
index 0000000000..e86742b8f2
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_initial_scale_1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>initial-scale=1 without width enables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>initial-scale=1</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function initial_scale_1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(info.autoSize,
+ "initial-scale=1 without width should enable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width.html
new file mode 100644
index 0000000000..6c950185bc
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>invalid width enables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=-1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=-1</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function invalid_width() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(info.autoSize, "invalid width should enable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width_and_fixed_height.html b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width_and_fixed_height.html
new file mode 100644
index 0000000000..db68ecb6ec
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_auto_size_by_invalid_width_and_fixed_height.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>invalid width but with fixed height disables autoSize</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=-1,height=200">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=-1,height=200</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function invalid_width_and_fixed_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ ok(!info.autoSize,
+ "invalid width but with valid height should disable autoSize");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_change_content_among_multiple.html b/dom/base/test/meta_viewport/test_meta_viewport_change_content_among_multiple.html
new file mode 100644
index 0000000000..8ec88b8920
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_change_content_among_multiple.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>content attribute changes among multiple meta viewport tags</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta id="first" name="viewport" content="width=980">
+ <meta id="second" name="viewport" content="width=device-width, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function change_content_attribute() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // The second meta tag is the one we use.
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+
+ // Change the content of the first one.
+ // eslint-disable-next-line no-undef
+ first.setAttribute("content", "width=640");
+
+ // Now the first one is prior to the second one.
+ info = getViewportInfo(800, 480);
+ fuzzeq(info.defaultZoom, 800/640, "initial scale is calculated based on width");
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 640, "width is the default width");
+ is(info.height, 480*640/800, "height is proportional to displayHeight");
+
+ // Cleat the second content.
+ // eslint-disable-next-line no-undef
+ second.setAttribute("content", "");
+
+ // The second one is prior to the first one, but the content is empty so
+ // that we should behave as if there is no meta viewport tag.
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 0.25, "initial scale is clamped to the default mimumim scale");
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 980, "width should be 980");
+ is(info.height,588, "height is proportional to displayHeight");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_change_name.html b/dom/base/test/meta_viewport/test_meta_viewport_change_name.html
new file mode 100644
index 0000000000..84b9c321df
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_change_name.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>name attribute changes</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta id="viewport" name="initial-name" content="width=device-width, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function change_name_attribute() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // There is no valid <meta name="viewport"> so that viewport info values
+ // are the same as values in test_meta_viewport0.html.
+ is(info.defaultZoom, 0.25, "initial scale is clamped to the default mimumim scale");
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 980, "width is the default width");
+ is(info.height, 588, "height is proportional to displayHeight");
+ is(info.autoSize, false, "autoSize is disabled by default");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ // Now it's a valid viewport.
+ // eslint-disable-next-line no-undef
+ viewport.setAttribute("name", "viewport");
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+
+ // Now it's invalid again, but we retain the state.
+ // eslint-disable-next-line no-undef
+ viewport.setAttribute("name", "other");
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_change_name_among_multiple.html b/dom/base/test/meta_viewport/test_meta_viewport_change_name_among_multiple.html
new file mode 100644
index 0000000000..ca41577bbe
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_change_name_among_multiple.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>name attribute changes among multiple meta viewport tags</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=980">
+ <meta id="viewport" name="initial-name" content="width=device-width, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script>
+ "use strict";
+
+ add_task(async function change_name_attribute() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+ let viewport = document.getElementById("viewport");
+
+ let info = getViewportInfo(800, 480);
+ // The "width=980" content is a valid one.
+ fuzzeq(info.defaultZoom, 800/980, "initial scale is calculated based on width");
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 980, "width is the default width");
+ is(info.height, 588, "height is proportional to displayHeight");
+
+ // Now the second meta tag is a valid viewport.
+ viewport.setAttribute("name", "viewport");
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+
+ // Now it's invalid again, but it's retained.
+ viewport.setAttribute("name", "other");
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_device_width.html b/dom/base/test/meta_viewport/test_meta_viewport_device_width.html
new file mode 100644
index 0000000000..0e1f2f1dac
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_device_width.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>device-width in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function device_width() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_0_5.html b/dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_0_5.html
new file mode 100644
index 0000000000..fc3192c854
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_0_5.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>device-width with initial-scale=0.5 in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width, initial-scale=0.5">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width, initial-scale=0.5</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function device_width_with_initial_scale_0_5() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 1600, "width should be the display width / initial-scale");
+ is(info.height, 960, "height should be the display height / initial-scale");
+ is(info.defaultZoom, 0.5, "initial-scale should be 0.5");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_2.html b/dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_2.html
new file mode 100644
index 0000000000..e701266e60
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_device_width_with_initial_scale_2.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>device-width with initial-scale=2 in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width, initial-scale=2">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width, initial-scale=2</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function device_width_with_initial_scale_2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // In the case device is specified, max-width isn't 'extend-to-zoom', it's
+ // the display width, and if the initial-scale is greater than 1,
+ // min-width will be the same as max-width because extend-width will be
+ // less than the display width, thus the final width should be the display
+ // width.
+ is(info.width, 800, "width should be the display width");
+ is(info.height, 480, "height should be the display height");
+ is(info.defaultZoom, 2, "initial-scale should be 2");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_empty_content_and_valid_content_tags.html b/dom/base/test/meta_viewport/test_meta_viewport_empty_content_and_valid_content_tags.html
new file mode 100644
index 0000000000..6de2e08c40
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_empty_content_and_valid_content_tags.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>a valid meta viewport tag and empty content attribute viewport tag</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400">
+ <meta name="viewport" content="">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function multiple_viewport_tags() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // The empty content attribute meta tag should be valid, which means
+ // it supersedes the first `width=400`.
+ is(info.width, 980, "width should be default, 980");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_fit.html b/dom/base/test/meta_viewport/test_meta_viewport_fit.html
new file mode 100644
index 0000000000..e86ad817d6
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_fit.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport viewport-fit test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="viewport-fit=cover">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>viewport-fit=cover</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let viewportFit = SpecialPowers.getDOMWindowUtils(window).getViewportFitInfo();
+ is(viewportFit, "cover", "viewport-fit is cover correctly");
+
+ let elements = document.getElementsByTagName("meta");
+ for (let meta of elements) {
+ if (meta.getAttribute("name") == "viewport") {
+ meta.setAttribute("content", "viewport-fit=contain");
+ }
+ }
+
+ viewportFit = SpecialPowers.getDOMWindowUtils(window).getViewportFitInfo();
+ is(viewportFit, "contain", "viewport-fit is contain correctly");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_fit_multiple.html b/dom/base/test/meta_viewport/test_meta_viewport_fit_multiple.html
new file mode 100644
index 0000000000..e204bb70f6
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_fit_multiple.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>multiple meta viewport viewport-fit test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="viewport-fit=cover">
+ <meta name="viewport" content="width=device-width">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>viewport-fit=cover</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let viewportFit = SpecialPowers.getDOMWindowUtils(window).getViewportFitInfo();
+ is(viewportFit, "auto", "No viewport-fit in last meta viewport. So auto is applied");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_fixed_width_and_zero_display_width.html b/dom/base/test/meta_viewport/test_meta_viewport_fixed_width_and_zero_display_width.html
new file mode 100644
index 0000000000..e649ad9fcd
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_fixed_width_and_zero_display_width.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Fixed meta viewport width, zero display width</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=100">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>Fixed meta viewport width, zero display width</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function valid_width() {
+ // We choose a 2.5 scaleRatio here to make clear that the later check
+ // of the viewport height is getting a scaled value.
+ await SpecialPowers.pushPrefEnv(scaleRatio(2.5));
+
+ // We request a zero-width viewport because that triggers a special
+ // codepath that sets the viewport height to the scaled display height.
+ let info = getViewportInfo(0, 500);
+ is(info.width, 100, "width should be 100");
+ is(info.height, 200, "height should be 200, since 500 / 2.5 = 200");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_0_5.html b/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_0_5.html
new file mode 100644
index 0000000000..99fb5c1d36
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_0_5.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>initial-scale=0.5 in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="initial-scale=0.5">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>initial-scale=0.5</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function initial_scale_0_5() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // 'min-width' is 'display width / initial-scale', thus the value will be
+ // bigger than the display width in the case where the initial-scale is
+ // less than 1, thus the final viewport width will be the 'min-width'.
+ // See 'Resolve initial width and height from min/max descriptors' section
+ // in the spec for more detail.
+ // height is calculated by the same rule.
+ // https://drafts.csswg.org/css-device-adapt/#resolve-initial-width-height
+ is(info.width, 1600, "width should be scaled by 1 / initial-scale");
+ is(info.height, 960, "height should be scaled by 1 / initial-scale");
+ is(info.defaultZoom, 0.5, "initial-scale should be 0.5");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_2.html b/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_2.html
new file mode 100644
index 0000000000..22f0adc061
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_2.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>initial-scale=2 in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="initial-scale=2">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>initial-scale=2</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function initial_scale_2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 400, "width should be scaled by 1 / initial-scale");
+ is(info.height, 240, "height should be scaled by 1 / initial-scale");
+ is(info.defaultZoom, 2, "initial-scale should be 2");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_with_trailing_characters.html b/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_with_trailing_characters.html
new file mode 100644
index 0000000000..5939691cb5
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_initial_scale_with_trailing_characters.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>initial-scale with trailing characters in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="initial-scale=1.0/">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>initial-scale=1.0/</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function initial_scale_with_trailing_characters() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 800, "width should be scaled by 1 / initial-scale");
+ is(info.height, 480, "height should be scaled by 1 / initial-scale");
+ is(info.defaultZoom, 1, "initial-scale should be 1");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_insert_before_existing_tag.html b/dom/base/test/meta_viewport/test_meta_viewport_insert_before_existing_tag.html
new file mode 100644
index 0000000000..e2162c81f8
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_insert_before_existing_tag.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>interting a meta viewport tag before existing one</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=980">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function multiple_viewport_tags() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ const meta = document.createElement("meta");
+ meta.setAttribute("name", "viewport");
+ meta.setAttribute("content", "initial-scale=1,maximum-scale=1");
+ document.head.insertBefore(meta, document.querySelector("meta[name=viewport]"));
+
+ let info = getViewportInfo(800, 480);
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ is(info.maxZoom, 1, "maximum scale is 1");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0.html b/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0.html
new file mode 100644
index 0000000000..893f3128d9
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=0">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width, minimum-scale=1, maximum-scale=0</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.maxZoom, 1, "maximum_scale should be clamped");
+ is(info.defaultZoom, 1, "initial scale should be 1");
+ is(info.minZoom, 1, "minimum scale should be 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0_5.html b/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0_5.html
new file mode 100644
index 0000000000..7f17ef146e
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_0_5.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>maximum-scale=0.5 in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="maximum-scale=0.5">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>maximum-scale=0.5</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function maximum_scale_0_5() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // In the case where the maximum-scale is less than 1 and there is no
+ // initial-scale or initial-scale is NOT greater than the maximum-scale,
+ // 'min-width' will be bigger than the display width.
+ is(info.width, 1600, "width should be scaled by 1 / maximum-scale");
+ is(info.height, 960, "height should be scaled by 1 / maximum-scale");
+ is(info.maxZoom, 0.5, "maximum-scale should be 0.5");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_2.html b/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_2.html
new file mode 100644
index 0000000000..2fe3baf27d
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_maximum_scale_2.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>maximum-scale=2 in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="maximum-scale=2">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>maximum-scale=2</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function maximum_scale_2() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 980, "without specified width, we get default width");
+ is(info.height, 588, "without specified width, height is scaled in aspect ratio to default width");
+ is(info.maxZoom, 2, "maximum-scale should be 2");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_multiple_tags.html b/dom/base/test/meta_viewport/test_meta_viewport_multiple_tags.html
new file mode 100644
index 0000000000..816dd62061
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_multiple_tags.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>multilple meta viewport tags</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=980">
+ <meta name="viewport" content="initial-scale=1,maximum-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function multiple_viewport_tags() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ is(info.maxZoom, 1, "maximum scale is 1");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_negative_height.html b/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_negative_height.html
new file mode 100644
index 0000000000..e458cbc8dd
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_negative_height.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>negative width and height in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=-400, height=-240">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=-400, height=-240</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function negative_width_and_negative_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // negative width and height should be ignored, then display width and
+ // height are used for viewport.
+ is(info.width, 800, "width should be the display width");
+ is(info.height, 480, "height should be the display height");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_no_height.html b/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_no_height.html
new file mode 100644
index 0000000000..2369f3b4f3
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_no_height.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>negative width in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=-400">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=-400</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function negative_width() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_valid_height.html b/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_valid_height.html
new file mode 100644
index 0000000000..579712504d
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_negative_width_and_valid_height.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>negative width and valid height in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=-300,height=240">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=-400, height=240</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function negative_width_and_valid_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 980, "width should be default when specified width is invalid");
+ is(info.height, 240, "height should be 240");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_no_content_and_valid_content_tags.html b/dom/base/test/meta_viewport/test_meta_viewport_no_content_and_valid_content_tags.html
new file mode 100644
index 0000000000..f5a78d9eec
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_no_content_and_valid_content_tags.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>a valid meta viewport tag and no content attribute viewport tag</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400">
+ <meta name="viewport">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function multiple_viewport_tags() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // The no content attribute meta tag should be ignored.
+ is(info.width, 400, "width should be 400");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_no_width_and_negative_height.html b/dom/base/test/meta_viewport/test_meta_viewport_no_width_and_negative_height.html
new file mode 100644
index 0000000000..0e0d37812b
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_no_width_and_negative_height.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>negative height in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="height=-200">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>height=-200</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function negative_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 980, "without specified width, we get default width");
+ is(info.height, 588, "without specified width, and invalid specified height, " +
+ "height is scaled in aspect ratio to default width");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_no_width_and_valid_height.html b/dom/base/test/meta_viewport/test_meta_viewport_no_width_and_valid_height.html
new file mode 100644
index 0000000000..a7be88ec40
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_no_width_and_valid_height.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>valid height in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="height=240">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>height=240</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function valid_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 980, "without specified width, we get default width");
+ is(info.height, 240, "height should be 240");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_remove_node.html b/dom/base/test/meta_viewport/test_meta_viewport_remove_node.html
new file mode 100644
index 0000000000..12104cdf50
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_remove_node.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>remove meta viewport node</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta id="viewport" name="viewport" content="width=device-width, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script>
+ "use strict";
+
+ add_task(async function remove_viewport_node() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+ let viewport = document.getElementById("viewport");
+
+ let info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+
+ // Now there is no <meta name="viewport">, but we still retain the info
+ // from the last one.
+ viewport.remove();
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_remove_node_from_multiple.html b/dom/base/test/meta_viewport/test_meta_viewport_remove_node_from_multiple.html
new file mode 100644
index 0000000000..b967967cc1
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_remove_node_from_multiple.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>remove a meta viewport node from multiple ones</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta id="willBeRemoved" name="viewport" content="width=980">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function remove_a_viewport_node() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+
+ // We use "width=980" for viewport stuff.
+ fuzzeq(info.defaultZoom, 800/980, "initial scale is calculated based on width");
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 980, "width is the default width");
+ is(info.height, 588, "height is proportional to displayHeight");
+ is(info.autoSize, false, "autoSize is disabled by default");
+ is(info.allowZoom, true, "zooming is enabled by default");
+
+ document.getElementById("willBeRemoved").remove();
+ info = getViewportInfo(800, 480);
+
+ // Now it was removed, but we remain the same.
+ fuzzeq(info.defaultZoom, 800/980, "initial scale is calculated based on width");
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 980, "width is the default width");
+ is(info.height, 588, "height is proportional to displayHeight");
+ is(info.autoSize, false, "autoSize is disabled by default");
+ is(info.allowZoom, true, "zooming is enabled by default");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_removing_content_attribute.html b/dom/base/test/meta_viewport/test_meta_viewport_removing_content_attribute.html
new file mode 100644
index 0000000000..784a503e9f
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_removing_content_attribute.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>removing content attribute</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400">
+ <meta name="viewport" content="width=800">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script>
+ "use strict";
+
+ add_task(async function multiple_viewport_tags() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ // The latter meta viewport tag is used.
+ is(info.width, 800, "width should be 800");
+
+ const secondMeta =
+ document.querySelector("meta[name=viewport][content='width=800']");
+ secondMeta.removeAttribute("content");
+
+ info = getViewportInfo(800, 480);
+ // The latter meta viewport tag is still used.
+ is(info.width, 800, "width should be 800");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_replace_content.html b/dom/base/test/meta_viewport/test_meta_viewport_replace_content.html
new file mode 100644
index 0000000000..202c62362b
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_replace_content.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>replace meta viewport content</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta id="viewport" name="viewport" content="width=device-width, initial-scale=1">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function replace_content() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ info = getViewportInfo(800, 480);
+ is(info.defaultZoom, 1, "initial zoom is 1");
+ is(info.width, 800, "width should be 800");
+ is(info.height, 480, "height should be 480");
+
+ // Now the content has only 'width=1080'.
+ // eslint-disable-next-line no-undef
+ viewport.setAttribute("content", "width=1080");
+ info = getViewportInfo(800, 480);
+
+ fuzzeq(info.defaultZoom, 800/1080, "initial scale is calculated by the given width");
+ is(info.minZoom, 0.25, "minimum scale defaults to the absolute minimum");
+ is(info.maxZoom, 10, "maximum scale defaults to the absolute maximum");
+ is(info.width, 1080, "width is the given width");
+ is(info.height, 480*1080/800, "height is proportional to displayHeight");
+ is(info.autoSize, false, "autoSize is disabled by default");
+ is(info.allowZoom, true, "zooming is enabled by default");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_tiny_display_size.html b/dom/base/test/meta_viewport/test_meta_viewport_tiny_display_size.html
new file mode 100644
index 0000000000..8e47fc677a
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_tiny_display_size.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>meta viewport test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=device-width">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=device-width</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function test1() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ // Check that the minimum viewport dimension of (200,40) are not enforced
+ // in cases where the display size itself has a smaller dimension.
+ let info = getViewportInfo(192, 32);
+ is(info.defaultZoom, 1, "initial zoom is 100%");
+ is(info.width, 192, "width is the same as the displayWidth");
+ is(info.height, 32, "height is the same as the displayHeight");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_negative_height.html b/dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_negative_height.html
new file mode 100644
index 0000000000..10bce57d87
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_negative_height.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>valid width and negative height in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400, height=-200">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=400, height=-200</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function valid_width_and_negative_height() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 400, "width should be 400");
+ is(info.height, 240, "height should be 240 which is the result of the " +
+ "display height * viewport width / display width");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_no_height.html b/dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_no_height.html
new file mode 100644
index 0000000000..b24ce680a7
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_valid_width_and_no_height.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>valid width in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=400</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function valid_width() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 400, "width should be 400");
+ is(info.height, 240, "height should be 240 which is the result of the " +
+ "display height * viewport width / display width");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/test_meta_viewport_width_with_trailing_characters.html b/dom/base/test/meta_viewport/test_meta_viewport_width_with_trailing_characters.html
new file mode 100644
index 0000000000..f3545d057b
--- /dev/null
+++ b/dom/base/test/meta_viewport/test_meta_viewport_width_with_trailing_characters.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>width with trailing characters in meta viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <meta name="viewport" content="width=400/">
+ <script src="viewport_helpers.js"></script>
+</head>
+<body>
+ <p>width=400/</p>
+ <script type="application/javascript">
+ "use strict";
+
+ add_task(async function width_with_trailing_characters() {
+ await SpecialPowers.pushPrefEnv(scaleRatio(1.0));
+
+ let info = getViewportInfo(800, 480);
+ is(info.width, 400, "width should be 400");
+ is(info.height, 240, "height should be 240 which is the result of the " +
+ "display height * viewport width / display width");
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/meta_viewport/viewport_helpers.js b/dom/base/test/meta_viewport/viewport_helpers.js
new file mode 100644
index 0000000000..d4d346b5d0
--- /dev/null
+++ b/dom/base/test/meta_viewport/viewport_helpers.js
@@ -0,0 +1,44 @@
+function scaleRatio(scale) {
+ return {
+ set: [
+ ["layout.css.devPixelsPerPx", "" + scale],
+ ["dom.meta-viewport.enabled", true],
+ ],
+ };
+}
+
+function getViewportInfo(aDisplayWidth, aDisplayHeight) {
+ let defaultZoom = {},
+ allowZoom = {},
+ minZoom = {},
+ maxZoom = {},
+ width = {},
+ height = {},
+ autoSize = {};
+
+ let cwu = SpecialPowers.getDOMWindowUtils(window);
+ cwu.getViewportInfo(
+ aDisplayWidth,
+ aDisplayHeight,
+ defaultZoom,
+ allowZoom,
+ minZoom,
+ maxZoom,
+ width,
+ height,
+ autoSize
+ );
+ return {
+ defaultZoom: defaultZoom.value,
+ minZoom: minZoom.value,
+ maxZoom: maxZoom.value,
+ width: width.value,
+ height: height.value,
+ autoSize: autoSize.value,
+ allowZoom: allowZoom.value,
+ };
+}
+
+function fuzzeq(a, b, msg) {
+ ok(Math.abs(a - b) < 1e-6, msg);
+}
diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini
new file mode 100644
index 0000000000..c04ccc7ac6
--- /dev/null
+++ b/dom/base/test/mochitest.ini
@@ -0,0 +1,1111 @@
+[DEFAULT]
+tags = condprof
+prefs =
+ formhelper.autozoom.force-disable.test-only=true
+support-files =
+ audio.ogg
+ iframe_bug962251.html
+ iframe_bug976673.html
+ iframe_main_bug1022229.html
+ iframe_sandbox_bug1022229.html
+ file_empty.html
+ iframe_postMessage_solidus.html
+ file_setname.html
+ 345339_iframe.html
+ Ahem.ttf
+ accesscontrol.resource
+ accesscontrol.resource^headers^
+ badContentType.eventsource
+ badContentType.eventsource^headers^
+ badHTTPResponseCode.eventsource
+ badHTTPResponseCode.eventsource^headers^
+ badMessageEvent.eventsource
+ badMessageEvent.eventsource^headers^
+ badMessageEvent2.eventsource
+ badMessageEvent2.eventsource^headers^
+ bug282547.sjs
+ bug298064-subframe.html
+ bug313646.txt
+ bug382113_object.html
+ bug403852_fileOpener.js
+ bug419132.html
+ bug426308-redirect.sjs
+ bug435425.sjs
+ bug435425_redirect.sjs
+ bug444322.js
+ bug444322.txt
+ bug455629-helper.svg
+ bug457746.sjs
+ bug461735-post-redirect.js
+ bug461735-redirect1.sjs
+ bug461735-redirect2.sjs
+ bug466080.sjs
+ bug466409-empty.css
+ bug466409-page.html
+ bug475156.sjs
+ bug482935.sjs
+ bug540854.sjs
+ bug578096LoadChromeScript.js
+ bug638112-response.txt
+ bug638112.sjs
+ bug696301-script-1.js
+ bug696301-script-1.js^headers^
+ bug696301-script-2.js
+ bug704320.sjs
+ bug704320_counter.sjs
+ bug819051.sjs
+ bug1576154.sjs
+ chrome/bug418986-1.js
+ copypaste.js
+ delayedServerEvents.sjs
+ eventsource_message.sjs
+ eventsource_reconnect.sjs
+ eventsource.resource
+ eventsource.resource^headers^
+ eventsource_redirect.resource
+ eventsource_redirect.resource^headers^
+ eventsource_redirect_to.resource
+ eventsource_redirect_to.resource^headers^
+ eventsource_worker.js
+ file_bug1091883_frame.html
+ file_bug1091883_subframe.html
+ file_bug1091883_target.html
+ file_bug28293.sjs
+ file_bug326337.xml
+ file_bug326337_inner.html
+ file_bug326337_outer.html
+ file_bug416317.xhtml
+ file_bug426646-1.html
+ file_bug426646-2.html
+ file_bug428847-1.xhtml
+ file_bug428847-2.xhtml
+ file_bug498897.css
+ file_bug498897.html
+ file_bug498897.html^headers^
+ file_bug503481.sjs
+ file_bug503481b_inner.html
+ file_bug541937.html
+ file_bug541937.xhtml
+ file_bug557892.html
+ file_bug562137.txt
+ file_bug590812-ref.xhtml
+ file_bug590812.xml
+ file_bug590870.html
+ file_bug601803a.html
+ file_bug601803b.html
+ file_bug604660-1.xml
+ file_bug604660-2.xsl
+ file_bug604660-3.js
+ file_bug604660-4.js
+ file_bug604660-5.xml
+ file_bug604660-6.xsl
+ file_bug622088.sjs
+ file_bug622088_inner.html
+ file_bug675121.sjs
+ file_bug687859-16.js
+ file_bug687859-16.js^headers^
+ file_bug687859-bom.js
+ file_bug687859-bom.js^headers^
+ file_bug687859-charset.js
+ file_bug687859-http.js
+ file_bug687859-http.js^headers^
+ file_bug687859-inherit.js
+ file_bug692434.xml
+ file_bug704320_preload_attr.html
+ file_bug704320_preload_common.js
+ file_bug704320_preload_reuse.html
+ file_bug704320_redirect.html
+ file_bug707142_baseline.json
+ file_bug707142_bom.json
+ file_bug707142_utf-16.json
+ file_bug708620-2.html
+ file_bug708620.html
+ file_bug753278.html
+ file_bug769117.html
+ file_bug782342.txt
+ file_bug787778.sjs
+ file_bug869432.eventsource
+ file_bug869432.eventsource^headers^
+ file_bug907892.html
+ file_bug945152.jar
+ file_bug1274806.html
+ file_current_inner_window.html
+ file_domwindowutils_animation.html
+ file_domwindowutils_dynamic_toolbar.html
+ file_focus_shadow_dom.html
+ file_general_document.html
+ file_history_document_open.html
+ file_htmlserializer_1.html
+ file_htmlserializer_1_bodyonly.html
+ file_htmlserializer_1_format.html
+ file_htmlserializer_1_linebreak.html
+ file_htmlserializer_1_links.html
+ file_htmlserializer_1_nested_body.html
+ file_htmlserializer_1_no_body.html
+ file_htmlserializer_1_noflag.html
+ file_htmlserializer_1_noformatpre.html
+ file_htmlserializer_1_raw.html
+ file_htmlserializer_1_sibling_body.html
+ file_htmlserializer_1_sibling_body_only_body.html
+ file_htmlserializer_1_wrap.html
+ file_htmlserializer_2.html
+ file_htmlserializer_2_basic.html
+ file_htmlserializer_ipv6.html
+ file_htmlserializer_ipv6_out.html
+ file_lock_orientation_with_pending_fullscreen.html
+ file_mozfiledataurl_img.jpg
+ file_restrictedEventSource.sjs
+ file_settimeout_inner.html
+ file_timer_flood.html
+ file_viewport_scroll_quirks.html
+ file_viewport_scroll_xml.xml
+ file_window_close.html
+ file_window_close_2.html
+ file_x-frame-options_main.html
+ file_x-frame-options_page.sjs
+ file_xhtmlserializer_1.xhtml
+ file_xhtmlserializer_1_bodyonly.xhtml
+ file_xhtmlserializer_1_format.xhtml
+ file_xhtmlserializer_1_linebreak.xhtml
+ file_xhtmlserializer_1_links.xhtml
+ file_xhtmlserializer_1_nested_body.xhtml
+ file_xhtmlserializer_1_no_body.xhtml
+ file_xhtmlserializer_1_noflag.xhtml
+ file_xhtmlserializer_1_noformatpre.xhtml
+ file_xhtmlserializer_1_raw.xhtml
+ file_xhtmlserializer_1_sibling_body.xhtml
+ file_xhtmlserializer_1_sibling_body_only_body.xhtml
+ file_xhtmlserializer_1_wrap.xhtml
+ file_xhtmlserializer_2.xhtml
+ file_xhtmlserializer_2_basic.xhtml
+ file_xhtmlserializer_2_enthtml.xhtml
+ file_xhtmlserializer_2_entw3c.xhtml
+ file_xhtmlserializer_2_latin1.xhtml
+ file_youtube_flash_embed.html
+ forRemoval.resource
+ forRemoval.resource^headers^
+ formReset.html
+ invalid_accesscontrol.resource
+ invalid_accesscontrol.resource^headers^
+ script-1_bug597345.sjs
+ script-2_bug597345.js
+ script_bug602838.sjs
+ send_gzip_content.sjs
+ somedatas.resource
+ somedatas.resource^headers^
+ variable_style_sheet.sjs
+ w3element_traversal.svg
+ wholeTexty-helper.xml
+ referrerHelper.js
+ file_audioLoop.html
+ file_webaudio_startstop.html
+ referrer_helper.js
+ referrer_testserver.sjs
+ script_postmessages_fileList.js
+ common_postMessages.js
+ iframe_postMessages.html
+ worker_postMessages.js
+ test_anonymousContent_style_csp.html^headers^
+ file_explicit_user_agent.sjs
+ referrer_change_server.sjs
+ file_change_policy_redirect.html
+ file_bug1198095.js
+ file_bug1250148.sjs
+ file_bug1268962.sjs
+ iframe_meta_refresh.sjs
+ !/dom/security/test/cors/file_CrossSiteXHR_server.sjs
+ !/image/test/mochitest/blue.png
+ script_bug1238440.js
+ intersectionobserver_iframe.html
+ intersectionobserver_cross_domain_iframe.html
+ intersectionobserver_window.html
+ object_bug353334.html
+ embed_bug455472.html
+ object_bug455472.html
+ iframe1_bug431701.html
+ iframe2_bug431701.html
+ iframe3_bug431701.html
+ iframe4_bug431701.xml
+ iframe5_bug431701.xml
+ iframe6_bug431701.xml
+ iframe7_bug431701.xml
+ iframe1_bug426646.html
+ iframe2_bug426646.html
+ iframe_shared_compartment2a.html
+ iframe_shared_compartment2b.html
+ file1_setting_opener.html
+ file2_setting_opener.html
+ file3_setting_opener.html
+ file4_setting_opener.html
+ PASS.html
+ FAIL.html
+ !/dom/animation/test/testcommon.js
+ !/dom/events/test/event_leak_utils.js
+ ../../../toolkit/components/pdfjs/test/file_pdfjs_test.pdf
+ green.png
+ slow.sjs
+
+[test_anchor_area_referrer.html]
+skip-if =
+ http3
+[test_anchor_area_referrer_changing.html]
+skip-if =
+ http3
+[test_anchor_area_referrer_invalid.html]
+skip-if =
+ http3
+[test_anchor_area_referrer_rel.html]
+skip-if =
+ http3
+[test_anonymousContent_api.html]
+[test_anonymousContent_append_after_reflow.html]
+[test_anonymousContent_canvas.html]
+skip-if = headless # Bug 1405867
+[test_anonymousContent_insert.html]
+[test_anonymousContent_manipulate_content.html]
+[test_anonymousContent_set_style.html]
+[test_anonymousContent_style_csp.html]
+[test_appname_override.html]
+[test_async_setTimeout_stack.html]
+[test_async_setTimeout_stack_across_globals.html]
+[test_base.xhtml]
+skip-if =
+ http3
+[test_bug1433073.html]
+skip-if = (os == "android" || headless) # See
+[test_bug1730284.html]
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1632196 and
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1632438.
+[test_bug1739957.html]
+support-files =
+ bug1739957.sjs
+[test_bug1784187.html]
+[test_bug1799354.html]
+[test_bug5141.html]
+[test_bug28293.html]
+[test_bug28293.xhtml]
+[test_bug51034.html]
+[test_bug116083.html]
+skip-if = headless # fails in clipboard mode
+[test_bug166235.html]
+skip-if = headless # headless != clipboard
+[test_bug1639328.html]
+support-files = file_bug1639328.html
+[test_bug199959.html]
+[test_bug218236.html]
+[test_bug218277.html]
+[test_bug238409.html]
+[test_bug254337.html]
+[test_bug270145.xhtml]
+[test_bug276037-1.html]
+[test_bug276037-2.xhtml]
+[test_bug282547.html]
+[test_bug298064.html]
+[test_bug300992.html]
+[test_bug311681.xml]
+[test_bug313646.html]
+[test_bug320799.html]
+[test_bug322317.html]
+[test_bug326337.html]
+skip-if =
+ http3
+[test_bug331959.html]
+[test_bug333064.html]
+skip-if = headless # Headless: Bug 1405868
+[test_bug333198.html]
+[test_bug333673.html]
+[test_bug337631.html]
+[test_bug338541.xhtml]
+[test_bug338583.html]
+skip-if =
+ http3
+[test_bug338679.html]
+[test_bug339494.html]
+[test_bug339494.xhtml]
+[test_bug343596.html]
+[test_bug345339.html]
+skip-if =
+ http3
+[test_bug346485.html]
+[test_bug352728.html]
+[test_bug352728.xhtml]
+[test_bug353334.html]
+[test_bug355026.html]
+[test_bug357450.html]
+support-files = file_bug357450.js
+[test_bug357450.xhtml]
+[test_bug357450_svg.xhtml]
+[test_bug357509.html]
+[test_bug358660.html]
+[test_bug362391.xhtml]
+[test_bug364092.xhtml]
+[test_bug364413.xhtml]
+[test_bug366944.html]
+[test_bug366946.html]
+[test_bug367164.html]
+[test_bug368972.html]
+[test_bug371576-2.html]
+[test_bug371576-3.html]
+[test_bug371576-4.html]
+[test_bug371576-5.html]
+[test_bug372086.html]
+[test_bug372964-2.html]
+[test_bug372964.html]
+[test_bug373181.xhtml]
+[test_bug375314.html]
+[test_bug375314-2.html]
+skip-if =
+ xorigin # Hangs, [Exception... "Component returned failure code: 0xc1f30100 (NS_ERROR_FACTORY_EXISTS) [nsIComponentRegistrar.registerFactory]" nsresult: "0xc1f30100 (NS_ERROR_FACTORY_EXISTS)" location: "JS frame :: createChromeScript :: createChromeScript :: line 40" data: no]
+ http3
+[test_bug378969.html]
+[test_bug380418.html]
+support-files = test_bug380418.html^headers^
+[test_bug382113.html]
+[test_bug382871.html]
+[test_bug384003.xhtml]
+[test_bug390219.html]
+[test_bug390735.html]
+[test_bug392318.html]
+[test_bug392511.html]
+[test_bug393968.html]
+[test_bug395915.html]
+[test_bug397234.html]
+[test_bug398243.html]
+skip-if =
+ http3
+[test_bug401662.html]
+[test_bug402150.html]
+support-files = test_bug402150.html^headers^
+[test_bug403841.html]
+[test_bug403852.html]
+[test_bug403868.xml]
+[test_bug405182.html]
+[test_bug409380.html]
+[test_bug410229.html]
+[test_bug413974.html]
+[test_bug414190.html]
+[test_bug415860.html]
+[test_bug416317-1.html]
+[test_bug416317-2.html]
+[test_bug416383.html]
+[test_bug417255.html]
+[test_bug417384.html]
+[test_bug418214.html]
+[test_bug418986-1.html]
+[test_bug419132.html]
+[test_bug420609.xhtml]
+[test_bug420700.html]
+[test_bug421602.html]
+[test_bug422403-1.html]
+skip-if =
+ http3
+[test_bug422403-2.xhtml]
+[test_bug422537.html]
+skip-if =
+ http3
+[test_bug424212.html]
+[test_bug424359-1.html]
+skip-if =
+ http3
+[test_bug424359-2.html]
+[test_bug426308.html]
+skip-if =
+ http3
+[test_bug426646.html]
+skip-if =
+ http3
+[test_bug428847.html]
+skip-if =
+ http3
+[test_bug431082.html]
+[test_bug431701.html]
+[test_bug431833.html]
+[test_bug433533.html]
+[test_bug433662.html]
+[test_bug435425.html]
+skip-if =
+ http3
+[test_bug444322.html]
+[test_bug444546.html]
+disabled = Disabled for now. Mochitest is not reliable enough for these.
+support-files = bug444546.sjs
+[test_bug444722.html]
+[test_bug448993.html]
+[test_bug450160.html]
+[test_bug451376.html]
+[test_bug453521.html]
+[test_bug453736.html]
+[test_bug454325.html]
+[test_bug454326.html]
+[test_bug455472.html]
+[test_bug455629.html]
+skip-if =
+ http3
+[test_bug456262.html]
+[test_bug457746.html]
+[test_bug459424.html]
+[test_bug461555.html]
+[test_bug461735.html]
+skip-if =
+ http3
+[test_bug465767.html]
+[test_bug466080.html]
+skip-if =
+ http3
+[test_bug466409.html]
+[test_bug466751.xhtml]
+[test_bug469020.html]
+[test_bug469304.html]
+[test_bug473162-1.html]
+[test_bug473162-2.html]
+[test_bug475156.html]
+skip-if =
+ http3
+[test_bug482935.html]
+[test_bug484396.html]
+[test_bug493881.html]
+support-files = test_bug493881.js
+[test_bug498240.html]
+[test_bug498433.html]
+[test_bug498897.html]
+[test_bug499656.html]
+[test_bug499656.xhtml]
+[test_bug500937.html]
+[test_bug503473.html]
+disabled = Disabled due to making the harness time out
+support-files = file_bug503473-frame.sjs
+[test_bug503481.html]
+[test_bug503481b.html]
+[test_bug513194.html]
+[test_bug514487.html]
+[test_bug515401.html]
+skip-if =
+ http3
+[test_bug518104.html]
+support-files = file_bug518104.js
+[test_bug527896.html]
+[test_bug540854.html]
+[test_bug541937.html]
+[test_bug544642.html]
+[test_bug545644.html]
+[test_bug545644.xhtml]
+[test_bug548463.html]
+[test_bug553896.xhtml]
+[test_bug557892.html]
+[test_bug558726.html]
+[test_bug559526.html]
+[test_bug560780.html]
+[test_bug562137.html]
+[test_bug562169-1.html]
+[test_bug562169-2.html]
+[test_bug562652.html]
+[test_bug564047.html]
+[test_bug564863.xhtml]
+[test_bug567350.html]
+[test_bug574596.html]
+skip-if = toolkit == 'android'
+[test_bug578096.html]
+skip-if = (verify && (os == 'win'))
+[test_bug585978.html]
+[test_bug587931.html]
+[test_bug588990.html]
+[test_bug590812.html]
+skip-if =
+ (verify && !debug && (os == 'linux')) #bug 687032
+ http3
+[test_bug590870.html]
+skip-if =
+ http3
+[test_bug592366.html]
+[test_bug592829.html]
+[test_bug597345.html]
+[test_bug599295.html]
+skip-if =
+ http3
+[test_bug599588.html]
+[test_bug601803.html]
+skip-if =
+ http3
+[test_bug602838.html]
+[test_bug604592.html]
+[test_bug604660.html]
+[test_bug605982.html]
+[test_bug606729.html]
+[test_bug614058.html]
+[test_bug622088.html]
+[test_bug622117.html]
+support-files = !/gfx/layers/apz/test/mochitest/apz_test_utils.js
+[test_bug622246.html]
+support-files = !/gfx/layers/apz/test/mochitest/apz_test_utils.js
+[test_bug625722.html]
+[test_bug626262.html]
+[test_bug628938.html]
+[test_bug631615.html]
+[test_bug638112.html]
+skip-if =
+ http3
+[test_bug647518.html]
+[test_bug650001.html]
+[test_bug650776.html]
+[test_bug650784.html]
+[test_bug656283.html]
+[test_bug664916.html]
+[test_bug666604.html]
+[test_bug675121.html]
+[test_bug675166.html]
+[test_bug682463.html]
+[test_bug682554.html]
+[test_bug682592.html]
+[test_bug684671.html]
+[test_bug685798.html]
+[test_bug686449.xhtml]
+[test_bug687859.html]
+[test_bug690056.html]
+[test_bug692434.html]
+[test_bug693615.html]
+[test_bug693875.html]
+[test_bug694754.xhtml]
+[test_bug696301-1.html]
+skip-if =
+ http3
+[test_bug696301-2.html]
+skip-if =
+ http3
+[test_bug698381.html]
+[test_bug698384.html]
+[test_bug704063.html]
+[test_bug704320-1.html]
+skip-if =
+ http3
+[test_bug704320-2.html]
+skip-if =
+ http3
+[test_bug704320_policyset.html]
+skip-if =
+ http3
+[test_bug704320_policyset2.html]
+[test_bug704320_preload.html]
+skip-if =
+ http3
+[test_bug707142.html]
+[test_bug708620.html]
+[test_bug711047.html]
+[test_bug711180.html]
+[test_bug719533.html]
+[test_bug726364.html]
+[test_bug737087.html]
+[test_bug737565.html]
+[test_bug737612.html]
+[test_bug738108.html]
+[test_bug744830.html]
+[test_bug749367.html]
+[test_bug750096.html]
+[test_bug753278.html]
+[test_bug761120.html]
+[test_bug769117.html]
+skip-if =
+ fission && os == "android" # Bug 1827725
+[test_bug782342.html]
+[test_bug787778.html]
+[test_bug789315.html]
+[test_bug789856.html]
+[test_bug809003.html]
+[test_bug810494.html]
+[test_bug811701.html]
+[test_bug811701.xhtml]
+[test_bug813919.html]
+[test_bug814576.html]
+[test_bug819051.html]
+skip-if =
+ http3
+[test_bug820909.html]
+[test_bug864595.html]
+[test_bug868999.html]
+[test_bug869000.html]
+[test_bug869002.html]
+[test_bug869006.html]
+[test_bug876282.html]
+[test_bug891952.html]
+[test_bug894874.html]
+[test_bug895974.html]
+[test_bug907892.html]
+skip-if =
+ http3
+[test_bug913761.html]
+[test_bug922681.html]
+[test_bug927196.html]
+[test_bug962251.html]
+[test_bug976673.html]
+skip-if =
+ http3
+[test_bug982153.html]
+[test_bug999456.html]
+[test_bug1022229.html]
+skip-if =
+ http3
+[test_bug1025933.html]
+[test_bug1037687.html]
+support-files = test_bug1037687_subframe.html
+[test_bug1043106.html]
+[test_bug1057176.html]
+[test_bug1060938.html]
+[test_bug1064481.html]
+[test_bug1070015.html]
+[test_bug1075702.html]
+[test_bug1091883.html]
+skip-if =
+ http3
+[test_bug1100912.html]
+support-files = file_bug1100912.html
+[test_bug1101364.html]
+[test_bug1118689.html]
+[test_bug1126851.html]
+[test_bug1163743.html]
+skip-if =
+ http3
+[test_bug1165501.html]
+skip-if =
+ http3
+[test_bug1187157.html]
+[test_bug1198095.html]
+[test_bug1238440.html]
+[test_bug1250148.html]
+[test_bug1259588.html]
+[test_bug1268962.html]
+skip-if =
+ http3
+[test_bug1222633.html]
+skip-if =
+ http3
+[test_bug1667316.html]
+[test_bug1222633_link_update.html]
+skip-if =
+ http3
+[test_bug1274806.html]
+[test_bug1281963.html]
+[test_bug1295852.html]
+[test_bug1307730.html]
+[test_bug1308069.html]
+[test_bug1314032.html]
+[test_bug1318303.html]
+[test_bug1375050.html]
+[test_bug1381710.html]
+[test_bug1399605.html]
+[test_bug1404385.html]
+[test_bug1406102.html]
+[test_bug1421568.html]
+[test_bug1472427.html]
+[test_bug1499169.html]
+skip-if = toolkit == 'android' # Timeouts on android due to page closing issues with embedded pdf
+[test_bug1576154.html]
+[test_bug1632975.html]
+[test_bug1640766.html]
+support-files =
+ iframe1_bug1640766.html
+ iframe2_bug1640766.html
+skip-if =
+ http3
+[test_bug1648887.html]
+[test_caretPositionFromPoint.html]
+[test_change_policy.html]
+skip-if =
+ http3
+[test_clearTimeoutIntervalNoArg.html]
+[test_clipboard_nbsp.html]
+[test_constructor-assignment.html]
+[test_constructor.html]
+[test_content_iterator_post_order.html]
+[test_content_iterator_pre_order.html]
+[test_content_iterator_subtree.html]
+[test_copyimage.html]
+skip-if = toolkit == 'android'
+ headless #bug 904183
+[test_copypaste.html]
+skip-if = toolkit == 'android'
+ headless #bug 904183
+[test_copypaste.xhtml]
+skip-if = headless #bug 904183
+[test_copypaste_disabled.html]
+support-files = !/gfx/layers/apz/test/mochitest/apz_test_utils.js
+[test_createHTMLDocument.html]
+[test_data_uri.html]
+[test_document.all_iteration.html]
+[test_document.all_unqualified.html]
+[test_document_constructor.html]
+[test_document_importNode_document.html]
+[test_custom_element.html]
+[test_custom_element_reflector.html]
+[test_current_inner_window.html]
+skip-if =
+ http3
+[test_document_wireframe.html]
+skip-if =
+ !sessionHistoryInParent
+ http3
+[test_domparser_null_char.html]
+[test_domparsing.html]
+[test_domrequest.html]
+[test_domwindowutils.html]
+skip-if = toolkit == 'android' # Bug 1525959
+[test_element.matches.html]
+[test_element_closest.html]
+[test_elementTraversal.html]
+[test_embed_xorigin_document.html]
+skip-if =
+ http3
+[test_encodeToStringWithMaxLength.html]
+[test_encodeToStringWithRequiresReinitAfterOutput.html]
+[test_EventSource_redirects.html]
+skip-if =
+ http3
+[test_eventsource_event_listener_leaks.html]
+[test_eventsourceservice_basic.html]
+skip-if =
+ http3
+[test_eventsourceservice_reconnect_error.html]
+skip-if =
+ http3
+[test_eventsourceservice_status_error.html]
+[test_eventsourceservice_worker.html]
+skip-if =
+ http3
+[test_explicit_user_agent.html]
+[test_find.html]
+[test_find_nac.html]
+[test_find_bug1601118.html]
+[test_find_bug1654683.html]
+[test_focus_keyboard_event.html]
+skip-if =
+ http3
+[test_focus_shadow_dom_root.html]
+[test_focus_shadow_dom.html]
+[test_focus_scrollable_input.html]
+[test_focus_scrollable_fieldset.html]
+[test_focus_scroll_padding_tab.html]
+[test_focus_design_mode.html]
+support-files =
+ file_focus_design_mode_inner.html
+[test_focus_display_none_xorigin_iframe.html]
+support-files =
+ file_focus_display_none_xorigin_iframe_inner.html
+skip-if =
+ http3
+[test_getAttribute_after_createAttribute.html]
+[test_getElementById.html]
+[test_getTranslationNodes.html]
+[test_getTranslationNodes_limit.html]
+[test_gsp-qualified.html]
+[test_gsp-quirks.html]
+[test_gsp-standards.html]
+[test_history_document_open.html]
+[test_history_state_null.html]
+[test_html_colors_quirks.html]
+[test_html_colors_standards.html]
+[test_htmlcopyencoder.html]
+[test_htmlcopyencoder.xhtml]
+[test_iframe_event_listener_leaks.html]
+skip-if = (processor == 'aarch64' && os == 'win') # aarch64 due to 1530895
+[test_iframe_referrer.html]
+skip-if =
+ http3
+[test_iframe_referrer_changing.html]
+skip-if =
+ http3
+[test_iframe_referrer_invalid.html]
+skip-if =
+ http3
+[test_Image_constructor.html]
+[test_innersize_scrollport.html]
+[test_input_vsync_alignment_lower_than_normal.html]
+[test_input_vsync_alignment_input_while_vsync.html]
+[test_input_vsync_alignment_inner_event_loop.html]
+[test_integer_attr_with_leading_zero.html]
+[test_intersectionobservers.html]
+skip-if =
+ http3
+[test_link_prefetch.html]
+skip-if =
+ http3
+[test_link_preload.html]
+skip-if =
+ http3
+[test_link_stylesheet.html]
+skip-if =
+ http3
+[test_location_href_unknown_protocol.html]
+support-files = file_location_href_unknown_protocol.html
+[test_lock_orientation_after_fullscreen.html]
+skip-if = toolkit != 'android' # Only run on Android.
+[test_lock_orientation_with_pending_fullscreen.html]
+skip-if = os == 'mac' || os == 'linux' || headless
+[test_meta_refresh_referrer.html]
+skip-if =
+ http3
+[test_mozMatchesSelector.html]
+[test_mutationobservers.html]
+[test_named_frames.html]
+[test_navigator_cookieEnabled.html]
+[test_navigator_hardwareConcurrency.html]
+[test_navigator_language.html]
+[test_navigatorPrefOverride.html]
+[test_NodeIterator_basics_filters.xhtml]
+skip-if = xorigin # JavaScript error: http://mochi.test:8888/tests/SimpleTest/SimpleTest.js, line 76: DataCloneError: The object could not be cloned.
+[test_NodeIterator_mutations_1.xhtml]
+[test_NodeIterator_mutations_2.html]
+[test_NodeIterator_mutations_3.html]
+[test_nested_event_loop_spin_and_idle_tasks.html]
+[test_nodelist_holes.html]
+[test_open_null_features.html]
+[test_openDialogChromeOnly.html]
+tags = openwindow
+[test_pasting_svg_image.html]
+skip-if = headless # Bug 1669923.
+[test_pdf_print.html]
+skip-if = toolkit == 'android' # We don't ship pdf.js on Android
+[test_plugin_freezing.html]
+skip-if = (os == 'win' && processor == 'aarch64')
+reason = Plugins are not supported on Windows/AArch64
+[test_postMessage_solidus.html]
+skip-if =
+ http3
+[test_postMessages_window.html]
+skip-if =
+ http3
+[test_postMessages_workers.html]
+[test_postMessages_broadcastChannel.html]
+[test_postMessages_messagePort.html]
+[test_postMessage_originAttributes.html]
+support-files = file_receiveMessage.html
+skip-if = true # Uses mismatched OriginAttributes for iframe (bug 1616353)
+[test_processing_instruction_update_stylesheet.xhtml]
+[test_progress_events_for_gzip_data.html]
+skip-if = tsan # Bug 1621323
+[test_pushState_structuredclone.html]
+scheme = https
+[test_range_bounds.html]
+[test_reentrant_flush.html]
+[test_root_iframe.html]
+[test_sandbox_and_document_uri.html]
+support-files = file_sandbox_and_document_uri.html
+[test_screen_orientation.html]
+[test_script_loader_crossorigin_data_url.html]
+[test_script_loader_js_cache.html]
+skip-if = verify
+support-files =
+ file_js_cache.html
+ file_js_cache_with_sri.html
+ file_js_cache_module.html
+ file_js_cache.js
+ file_module_js_cache.html
+ file_module_js_cache_with_sri.html
+ file_module_js_cache_no_module.html
+ file_module_js_cache.js
+ file_js_cache_save_after_load.html
+ file_js_cache_save_after_load.js
+ file_js_cache_syntax_error.html
+ file_js_cache_syntax_error.js
+[test_script_loader_js_cache_module.html]
+skip-if = verify
+support-files =
+ file_script_module_single.html
+ file_script_module_single.js
+ file_script_module_import.html
+ file_script_module_import.js
+ file_script_module_import_imported.js
+ file_script_module_import_multi.html
+ file_script_module_import_multi.js
+ file_script_module_import_multi_imported_once.js
+ file_script_module_import_multi_imported_twice.js
+ file_script_module_import_multi_elems.html
+ file_script_module_import_multi_elems_1.js
+ file_script_module_import_multi_elems_2.js
+ file_script_module_import_multi_elems_imported_once_1.js
+ file_script_module_import_multi_elems_imported_once_2.js
+ file_script_module_import_multi_elems_imported_once_3.js
+ file_script_module_import_multi_elems_imported_twice.js
+ file_script_module_import_and_element.html
+ file_script_module_import_and_element.js
+ file_script_module_import_and_element_imported_1.js
+ file_script_module_import_and_element_imported_2.js
+ file_script_module_import_and_element_imported_3.js
+ file_script_module_element_and_import.html
+ file_script_module_element_and_import.js
+ file_script_module_element_and_import_imported_1.js
+ file_script_module_element_and_import_imported_2.js
+ file_script_module_element_and_import_imported_3.js
+ file_script_module_dynamic_import.html
+ file_script_module_dynamic_import.js
+ file_script_module_dynamic_import_imported.js
+ file_script_module_dynamic_and_element.html
+ file_script_module_dynamic_and_element.js
+ file_script_module_dynamic_and_element_imported_1.js
+ file_script_module_dynamic_and_element_imported_2.js
+ file_script_module_dynamic_and_element_imported_3.js
+ file_script_module_element_and_dynamic.html
+ file_script_module_element_and_dynamic.js
+ file_script_module_element_and_dynamic_imported_1.js
+ file_script_module_element_and_dynamic_imported_2.js
+ file_script_module_element_and_dynamic_imported_3.js
+ file_script_module_dynamic_and_static.html
+ file_script_module_dynamic_and_static.js
+ file_script_module_dynamic_and_static_imported_1.js
+ file_script_module_dynamic_and_static_imported_2.js
+ file_script_module_dynamic_and_static_imported_3.js
+ file_script_module_static_and_dynamic.html
+ file_script_module_static_and_dynamic.js
+ file_script_module_static_and_dynamic_imported_1.js
+ file_script_module_static_and_dynamic_imported_2.js
+ file_script_module_static_and_dynamic_imported_3.js
+[test_script_loader_js_cache_module_sri.html]
+skip-if = verify
+support-files =
+ file_script_module_sri_basic.html
+ file_script_module_sri_basic_prep.html
+ file_script_module_sri_basic.js
+ file_script_module_sri_fallback.html
+ file_script_module_sri_fallback_prep.html
+ file_script_module_sri_fallback.js
+ file_script_module_sri_fallback_failure.html
+ file_script_module_sri_fallback_failure_prep.html
+ file_script_module_sri_fallback_failure.js
+ file_script_module_sri_elem_elem_1.html
+ file_script_module_sri_elem_elem_1_prep.html
+ file_script_module_sri_elem_elem_1.js
+ file_script_module_sri_elem_elem_2.html
+ file_script_module_sri_elem_elem_2_prep.html
+ file_script_module_sri_elem_elem_2.js
+ file_script_module_sri_elem_import.html
+ file_script_module_sri_elem_import_prep.html
+ file_script_module_sri_elem_import.js
+ file_script_module_sri_elem_import_imported.js
+ file_script_module_sri_import_elem.html
+ file_script_module_sri_import_elem_prep.html
+ file_script_module_sri_import_elem.js
+ file_script_module_sri_import_elem_imported.js
+ file_script_module_sri_import_elem_nopreload.html
+ file_script_module_sri_import_elem_nopreload_prep.html
+ file_script_module_sri_import_elem_nopreload.js
+ file_script_module_sri_import_elem_nopreload_imported.js
+ file_script_module_sri_elem_dynamic.html
+ file_script_module_sri_elem_dynamic_prep.html
+ file_script_module_sri_elem_dynamic.js
+ file_script_module_sri_elem_dynamic_imported.js
+ file_script_module_sri_dynamic_elem.html
+ file_script_module_sri_dynamic_elem_prep.html
+ file_script_module_sri_dynamic_elem.js
+ file_script_module_sri_dynamic_elem_imported.js
+ file_script_module_sri_dynamic_elem_nopreload.html
+ file_script_module_sri_dynamic_elem_nopreload_prep.html
+ file_script_module_sri_dynamic_elem_nopreload.js
+ file_script_module_sri_dynamic_elem_nopreload_imported.js
+[test_script_loader_js_cache_frames.html]
+skip-if = verify
+support-files =
+ file_script_module_frames_relay.js
+ file_script_module_frames_element.html
+ file_script_module_frames_element_save.html
+ file_script_module_frames_element_load.html
+ file_script_module_frames_element_shared.js
+ file_script_module_frames_import.html
+ file_script_module_frames_import_save.html
+ file_script_module_frames_import_save.js
+ file_script_module_frames_import_load.html
+ file_script_module_frames_import_load.js
+ file_script_module_frames_import_shared.js
+ file_script_module_frames_dynamic.html
+ file_script_module_frames_dynamic_save.html
+ file_script_module_frames_dynamic_save.js
+ file_script_module_frames_dynamic_load.html
+ file_script_module_frames_dynamic_load.js
+ file_script_module_frames_dynamic_shared.js
+[test_delazification_strategy.html]
+skip-if = (verify || ccov)
+support-files =
+ file_delazification_strategy.html
+ file_delazification_strategy.js
+[test_setInterval_from_start.html]
+[test_setInterval_uncatchable_exception.html]
+skip-if = debug == false
+[test_settimeout_extra_arguments.html]
+[test_settimeout_inner.html]
+[test_setTimeoutWith0.html]
+[test_setting_opener.html]
+[test_shared_compartment1.html]
+skip-if =
+ http3
+[test_shared_compartment2.html]
+skip-if =
+ http3
+[test_structuredclone_backref.html]
+[test_structuredclone_error.html]
+[test_style_cssText.html]
+[test_suppressed_events_and_scrolling.html]
+support-files =
+ file_suppressed_events_and_scrolling.html
+[test_suppressed_events_nested_iframe.html]
+skip-if =
+ os == "android"
+ http3
+support-files =
+ file_suppressed_events_top_xhr.html
+ file_suppressed_events_top_modalstate.html
+ file_suppressed_events_top.html
+ file_suppressed_events_middle.html
+ file_suppressed_events_inner.html
+ !/gfx/layers/apz/test/mochitest/apz_test_utils.js
+[test_suppressed_microtasks.html]
+skip-if =
+ debug || asan || verify || toolkit == 'android' # The test needs to run reasonably fast.
+[test_text_wholeText.html]
+[test_textnode_normalize_in_selection.html]
+[test_textnode_split_in_selection.html]
+[test_timeout_clamp.html]
+[test_timer_flood.html]
+[test_title.html]
+support-files = file_title.xhtml
+[test_toScreenRect.html]
+support-files = file_toScreenRect.html
+[test_treewalker_nextsibling.xml]
+[test_user_select.html]
+skip-if = os == "android" # Bug 1791049
+[test_viewport_metrics_on_landscape_content.html]
+support-files =
+ file_viewport_metrics_on_landscape_content.html
+[test_viewport_scroll.html]
+[test_viewsource_forbidden_in_object.html]
+[test_w3element_traversal.html]
+[test_w3element_traversal.xhtml]
+[test_w3element_traversal_svg.html]
+[test_warning_for_blocked_cross_site_request.html]
+skip-if =
+ http3
+[test_window_close.html]
+[test_window_constructor.html]
+[test_window_content.html]
+[test_window_cross_origin_props.html]
+skip-if =
+ http3
+[test_window_define_nonconfigurable.html]
+[test_window_define_symbol.html]
+[test_window_element_enumeration.html]
+[test_window_enumeration.html]
+[test_window_extensible.html]
+[test_window_focus_by_close_and_open.html]
+support-files = file_window_focus_by_close_and_open.html
+[test_window_indexing.html]
+[test_window_keys.html]
+[test_window_named_frame_enumeration.html]
+skip-if =
+ http3
+[test_window_own_props.html]
+[test_window_proto.html]
+[test_writable-replaceable.html]
+[test_x-frame-options.html]
+skip-if =
+ toolkit == 'android' && debug
+ xorigin # JavaScript error: http://mochi.test:8888/tests/dom/base/test/test_x-frame-options.html, line 48: TypeError: can't access property "textContent", this.content.document.getElementById(...) is null, JavaScript error: resource://gre/modules/ProcessSelector.jsm, line 56: TypeError: can't access property "tabCount", process is null
+ http3
+[test_youtube_flash_embed.html]
+skip-if =
+ http3
+# Please keep alphabetical order.
diff --git a/dom/base/test/moz.build b/dom/base/test/moz.build
new file mode 100644
index 0000000000..37cc3ab239
--- /dev/null
+++ b/dom/base/test/moz.build
@@ -0,0 +1,44 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPCSHELL_TESTS_MANIFESTS += [
+ "unit/xpcshell.ini",
+ "unit_ipc/xpcshell.ini",
+]
+
+MOCHITEST_MANIFESTS += [
+ "mochitest.ini",
+]
+
+MOCHITEST_CHROME_MANIFESTS += [
+ "chrome.ini",
+ "chrome/chrome.ini",
+]
+
+BROWSER_CHROME_MANIFESTS += [
+ "browser.ini",
+ "fmm/browser.ini",
+]
+
+TEST_DIRS += [
+ "fullscreen",
+ "gtest",
+ "jsmodules",
+ "jsmodules/importmaps",
+ "useractivation",
+ "meta_viewport",
+]
+
+TEST_HARNESS_FILES.testing.mochitest.tests.dom.base.test.chrome += [
+ "chrome/bug421622-referer.sjs",
+ "chrome/bug884693.sjs",
+ "chrome/nochrome_bug1346936.html",
+ "chrome/nochrome_bug1346936.js",
+ "chrome/nochrome_bug1346936.js^headers^",
+ "chrome/nochrome_bug765993.html",
+ "chrome/nochrome_bug765993.js",
+ "chrome/nochrome_bug765993.js^headers^",
+]
diff --git a/dom/base/test/object_bug353334.html b/dom/base/test/object_bug353334.html
new file mode 100644
index 0000000000..8e73c916c6
--- /dev/null
+++ b/dom/base/test/object_bug353334.html
@@ -0,0 +1 @@
+<body>test</body>
diff --git a/dom/base/test/object_bug455472.html b/dom/base/test/object_bug455472.html
new file mode 100644
index 0000000000..b2f3ae4f44
--- /dev/null
+++ b/dom/base/test/object_bug455472.html
@@ -0,0 +1 @@
+<script>parent.ran[1]=true</script>
diff --git a/dom/base/test/red.png b/dom/base/test/red.png
new file mode 100644
index 0000000000..a6e195d59c
--- /dev/null
+++ b/dom/base/test/red.png
Binary files differ
diff --git a/dom/base/test/referrerHelper.js b/dom/base/test/referrerHelper.js
new file mode 100644
index 0000000000..da3097b849
--- /dev/null
+++ b/dom/base/test/referrerHelper.js
@@ -0,0 +1,343 @@
+/**
+ * Listen for notifications from the child.
+ * These are sent in case of error, or when the loads we await have completed.
+ */
+window.addEventListener("message", function (event) {
+ if (event.data == "childLoadComplete") {
+ // all loads happen, continue the test.
+ advance();
+ } else if (event.data == "childOverload") {
+ // too many loads happened in a test frame, abort.
+ ok(false, "Too many load handlers called in test.");
+ SimpleTest.finish();
+ } else if (event.data.indexOf("fail-") == 0) {
+ // something else failed in the test frame, abort.
+ ok(false, "Child failed the test with error " + event.data.substr(5));
+ SimpleTest.finish();
+ }
+});
+
+/**
+ * helper to perform an XHR.
+ */
+function doXHR(url, onSuccess, onFail) {
+ var xhr = new XMLHttpRequest();
+ xhr.onload = function () {
+ if (xhr.status == 200) {
+ onSuccess(xhr);
+ } else {
+ onFail(xhr);
+ }
+ };
+ xhr.open("GET", url, true);
+ xhr.send(null);
+}
+
+/**
+ * This triggers state-resetting on the counter server.
+ */
+function resetCounter() {
+ doXHR(
+ "/tests/dom/base/test/bug704320_counter.sjs?reset",
+ advance,
+ function (xhr) {
+ ok(false, "Need to be able to reset the request counter");
+ SimpleTest.finish();
+ }
+ );
+}
+
+/**
+ * Grabs the results via XHR and passes to checker.
+ */
+function checkIndividualResults(testname, expected) {
+ doXHR(
+ "/tests/dom/base/test/bug704320_counter.sjs?results",
+ function (xhr) {
+ var results = JSON.parse(xhr.responseText);
+ info(xhr.responseText);
+
+ ok(
+ "img" in results,
+ testname + " test: some image loads required in results object."
+ );
+ is(
+ results.img.count,
+ 2,
+ testname + " Test: Expected 2 loads for image requests."
+ );
+
+ expected.forEach(function (ref) {
+ ok(
+ results.img.referrers.includes(ref),
+ testname +
+ " Test: Expected " +
+ ref +
+ " referrer policy in test, results were " +
+ JSON.stringify(results.img.referrers) +
+ "."
+ );
+ });
+ advance();
+ },
+ function (xhr) {
+ ok(false, "Can't get results from the counter server.");
+ SimpleTest.finish();
+ }
+ );
+}
+
+/**
+ * Grabs the results via XHR and checks them
+ */
+function checkExpectedGlobalResults(testName) {
+ var url = "bug704320.sjs?action=get-test-results";
+ doXHR(
+ url,
+ function (xhr) {
+ var response = JSON.parse(xhr.response);
+
+ for (type in response) {
+ for (scheme in response[type]) {
+ for (policy in response[type][scheme]) {
+ var expectedResult =
+ EXPECTED_RESULTS[type] === undefined
+ ? EXPECTED_RESULTS.default[scheme][policy]
+ : EXPECTED_RESULTS[type][scheme][policy];
+ is(
+ response[type][scheme][policy],
+ expectedResult,
+ type + " " + scheme + " " + policy
+ );
+ }
+ }
+ }
+ advance(testName);
+ },
+ function (xhr) {
+ ok(false, "Can't get results from the counter server.");
+ SimpleTest.finish();
+ }
+ );
+}
+
+var EXPECTED_RESULTS = {
+ // From docshell/base/nsDocShell.cpp:
+ // "If the document containing the hyperlink being audited was not retrieved
+ // over an encrypted connection and its address does not have the same
+ // origin as "ping URL", send a referrer."
+ "link-ping": {
+ // Same-origin
+ "http-to-http": {
+ "no-referrer": "",
+ "unsafe-url": "",
+ origin: "",
+ "origin-when-cross-origin": "",
+ "no-referrer-when-downgrade": "",
+ "same-origin": "",
+ "strict-origin": "",
+ "strict-origin-when-cross-origin": "",
+ },
+ "http-to-https": {
+ "no-referrer": "",
+ "unsafe-url":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url",
+ origin: "http://example.com/",
+ "origin-when-cross-origin": "http://example.com/",
+ "no-referrer-when-downgrade":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade",
+ "same-origin": "",
+ "strict-origin": "http://example.com/",
+ "strict-origin-when-cross-origin": "http://example.com/",
+ },
+ // Encrypted and not same-origin
+ "https-to-http": {
+ "no-referrer": "",
+ "unsafe-url": "",
+ origin: "",
+ "origin-when-cross-origin": "",
+ "no-referrer-when-downgrade": "",
+ "same-origin": "",
+ "strict-origin": "",
+ "strict-origin-when-cross-origin": "",
+ },
+ // Encrypted
+ "https-to-https": {
+ "no-referrer": "",
+ "unsafe-url": "",
+ origin: "",
+ "origin-when-cross-origin": "",
+ "no-referrer-when-downgrade": "",
+ "same-origin": "",
+ "strict-origin": "",
+ "strict-origin-when-cross-origin": "",
+ },
+ },
+ // form is tested in a 2nd level iframe.
+ form: {
+ "http-to-http": {
+ "no-referrer": "",
+ "unsafe-url":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url&type=form",
+ origin: "http://example.com/",
+ "origin-when-cross-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin&type=form",
+ "no-referrer-when-downgrade":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade&type=form",
+ "same-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=same-origin&type=form",
+ "strict-origin": "http://example.com/",
+ "strict-origin-when-cross-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=strict-origin-when-cross-origin&type=form",
+ },
+ "http-to-https": {
+ "no-referrer": "",
+ "unsafe-url":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url&type=form",
+ origin: "http://example.com/",
+ "origin-when-cross-origin": "http://example.com/",
+ "no-referrer-when-downgrade":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade&type=form",
+ "same-origin": "",
+ "strict-origin": "http://example.com/",
+ "strict-origin-when-cross-origin": "http://example.com/",
+ },
+ "https-to-http": {
+ "no-referrer": "",
+ "unsafe-url":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url&type=form",
+ origin: "https://example.com/",
+ "origin-when-cross-origin": "https://example.com/",
+ "no-referrer-when-downgrade": "",
+ "same-origin": "",
+ "strict-origin": "",
+ "strict-origin-when-cross-origin": "",
+ },
+ "https-to-https": {
+ "no-referrer": "",
+ "unsafe-url":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url&type=form",
+ origin: "https://example.com/",
+ "origin-when-cross-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin&type=form",
+ "no-referrer-when-downgrade":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade&type=form",
+ "same-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=same-origin&type=form",
+ "strict-origin": "https://example.com/",
+ "strict-origin-when-cross-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=strict-origin-when-cross-origin&type=form",
+ },
+ },
+ // window.location is tested in a 2nd level iframe.
+ "window.location": {
+ "http-to-http": {
+ "no-referrer": "",
+ "unsafe-url":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url&type=window.location",
+ origin: "http://example.com/",
+ "origin-when-cross-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin&type=window.location",
+ "no-referrer-when-downgrade":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade&type=window.location",
+ "same-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=same-origin&type=window.location",
+ "strict-origin": "http://example.com/",
+ "strict-origin-when-cross-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=http&policy=strict-origin-when-cross-origin&type=window.location",
+ },
+ "http-to-https": {
+ "no-referrer": "",
+ "unsafe-url":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url&type=window.location",
+ origin: "http://example.com/",
+ "origin-when-cross-origin": "http://example.com/",
+ "no-referrer-when-downgrade":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade&type=window.location",
+ "same-origin": "",
+ "strict-origin": "http://example.com/",
+ "strict-origin-when-cross-origin": "http://example.com/",
+ },
+ "https-to-http": {
+ "no-referrer": "",
+ "unsafe-url":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url&type=window.location",
+ origin: "https://example.com/",
+ "origin-when-cross-origin": "https://example.com/",
+ "no-referrer-when-downgrade": "",
+ "same-origin": "",
+ "strict-origin": "",
+ "strict-origin-when-cross-origin": "",
+ },
+ "https-to-https": {
+ "no-referrer": "",
+ "unsafe-url":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url&type=window.location",
+ origin: "https://example.com/",
+ "origin-when-cross-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin&type=window.location",
+ "no-referrer-when-downgrade":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade&type=window.location",
+ "same-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=same-origin&type=window.location",
+ "strict-origin": "https://example.com/",
+ "strict-origin-when-cross-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-2nd-level-iframe&scheme-from=https&scheme-to=https&policy=strict-origin-when-cross-origin&type=window.location",
+ },
+ },
+ default: {
+ "http-to-http": {
+ "no-referrer": "",
+ "unsafe-url":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url",
+ origin: "http://example.com/",
+ "origin-when-cross-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin",
+ "no-referrer-when-downgrade":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade",
+ "same-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=same-origin",
+ "strict-origin": "http://example.com/",
+ "strict-origin-when-cross-origin":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=strict-origin-when-cross-origin",
+ },
+ "http-to-https": {
+ "no-referrer": "",
+ "unsafe-url":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url",
+ origin: "http://example.com/",
+ "origin-when-cross-origin": "http://example.com/",
+ "no-referrer-when-downgrade":
+ "http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade",
+ "same-origin": "",
+ "strict-origin": "http://example.com/",
+ "strict-origin-when-cross-origin": "http://example.com/",
+ },
+ "https-to-http": {
+ "no-referrer": "",
+ "unsafe-url":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url",
+ origin: "https://example.com/",
+ "origin-when-cross-origin": "https://example.com/",
+ "no-referrer-when-downgrade": "",
+ "same-origin": "",
+ "strict-origin": "",
+ "strict-origin-when-cross-origin": "",
+ },
+ "https-to-https": {
+ "no-referrer": "",
+ "unsafe-url":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url",
+ origin: "https://example.com/",
+ "origin-when-cross-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin",
+ "no-referrer-when-downgrade":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade",
+ "same-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=same-origin",
+ "strict-origin": "https://example.com/",
+ "strict-origin-when-cross-origin":
+ "https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=strict-origin-when-cross-origin",
+ },
+ },
+};
diff --git a/dom/base/test/referrer_change_server.sjs b/dom/base/test/referrer_change_server.sjs
new file mode 100644
index 0000000000..d37cfb1e5f
--- /dev/null
+++ b/dom/base/test/referrer_change_server.sjs
@@ -0,0 +1,166 @@
+var BASE_URL = "example.com/tests/dom/base/test/referrer_change_server.sjs";
+
+function createTestUrl(aPolicy, aAction, aName) {
+ return (
+ "http://" +
+ BASE_URL +
+ "?" +
+ "action=" +
+ aAction +
+ "&" +
+ "policy=" +
+ aPolicy +
+ "&" +
+ "name=" +
+ aName +
+ "&" +
+ "type=link"
+ );
+}
+
+function createTest(aMetaPolicy, aReferrerPolicy, aName) {
+ return (
+ "<!DOCTYPE HTML>\n\
+ <html>" +
+ '<meta name="referrer" content="' +
+ aMetaPolicy +
+ '">' +
+ "<body>" +
+ '<a href="' +
+ createTestUrl(aReferrerPolicy, "test", aName + aReferrerPolicy) +
+ '" id="link">' +
+ aReferrerPolicy +
+ "</a>" +
+ "<script>" +
+ // LOAD EVENT (of the test)
+ // fires when the page is loaded, then click link
+ // first change meta referrer, then click link
+ 'window.addEventListener("load", function() {\n\
+ document.getElementsByName("referrer")[0].content = "' +
+ aReferrerPolicy +
+ '";\n\
+ document.getElementById("link").click();\n\
+ }.bind(window), false);' +
+ "</script>\n\
+ </body>\n\
+ </html>"
+ );
+}
+
+function createTest2(aMetaPolicy, aReferrerPolicy, aName) {
+ return (
+ "<!DOCTYPE HTML>\n\
+ <html>" +
+ '<meta name="referrer" content="' +
+ aMetaPolicy +
+ '">' +
+ "<body>" +
+ '<a href="' +
+ createTestUrl(aReferrerPolicy, "test", aName + aReferrerPolicy) +
+ '" id="link">' +
+ aReferrerPolicy +
+ "</a>" +
+ "<script>" +
+ // LOAD EVENT (of the test)
+ // fires when the page is loaded, then click link
+ // first change meta referrer, then click link
+ 'window.addEventListener("load", function() {\n\
+ document.getElementsByName("referrer")[0].setAttribute("content", "' +
+ aReferrerPolicy +
+ '");\n\
+ document.getElementById("link").click();\n\
+ }.bind(window), false);' +
+ "</script>\n\
+ </body>\n\
+ </html>"
+ );
+}
+
+function handleRequest(request, response) {
+ var sharedKey = "referrer_change_server.sjs";
+ var params = request.queryString.split("&");
+ var action = params[0].split("=")[1];
+
+ if (action === "resetState") {
+ var state = getSharedState(sharedKey);
+ state = {};
+ setSharedState(sharedKey, JSON.stringify(state));
+ response.write("");
+ return;
+ } else if (action === "test") {
+ // ?action=test&policy=origin&name=name
+ var policy = params[1].split("=")[1];
+ var name = params[2].split("=")[1];
+ var type = params[3].split("=")[1];
+ var result = getSharedState(sharedKey);
+
+ if (result === "") {
+ result = {};
+ } else {
+ result = JSON.parse(result);
+ }
+
+ if (!result.tests) {
+ result.tests = {};
+ }
+
+ var referrerLevel = "none";
+ var test = {};
+ if (request.hasHeader("Referer")) {
+ let referrer = request.getHeader("Referer");
+ if (referrer.indexOf("referrer_change_server") > 0) {
+ referrerLevel = "full";
+ } else if (referrer == "http://mochi.test:8888") {
+ referrerLevel = "origin";
+ }
+ test.referrer = request.getHeader("Referer");
+ } else {
+ test.referrer = "";
+ }
+ test.policy = referrerLevel;
+ test.expected = policy;
+
+ result.tests[name] = test;
+
+ setSharedState(sharedKey, JSON.stringify(result));
+
+ // forward link click to redirect URL to finish test
+ if (type === "link") {
+ var loc =
+ "https://example.com/tests/dom/base/test/file_change_policy_redirect.html";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+ }
+
+ return;
+ } else if (action === "get-test-results") {
+ // ?action=get-result
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(getSharedState(sharedKey));
+ return;
+ } else if (action === "generate-policy-test") {
+ // ?action=generate-policy-test&referrerPolicy=b64-encoded-string&name=name&newPolicy=b64-encoded-string
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ var referrerPolicy = unescape(params[1].split("=")[1]);
+ var name = unescape(params[2].split("=")[1]);
+ var newPolicy = params[3].split("=")[1];
+
+ response.write(createTest(referrerPolicy, newPolicy, name));
+ return;
+ } else if (action === "generate-policy-test2") {
+ // ?action=generate-policy-test2&referrerPolicy=b64-encoded-string&name=name&newPolicy=b64-encoded-string
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ var referrerPolicy = unescape(params[1].split("=")[1]);
+ var name = unescape(params[2].split("=")[1]);
+ var newPolicy = params[3].split("=")[1];
+
+ response.write(createTest2(referrerPolicy, newPolicy, name));
+ return;
+ } else {
+ response.write("I don't know action " + action);
+ return;
+ }
+}
diff --git a/dom/base/test/referrer_header.sjs b/dom/base/test/referrer_header.sjs
new file mode 100644
index 0000000000..29c324b8f6
--- /dev/null
+++ b/dom/base/test/referrer_header.sjs
@@ -0,0 +1,6 @@
+function handleRequest(request, response) {
+ response.setHeader("Referrer-Policy", "same-origin");
+ response.write(
+ '<!DOCTYPE HTML><html><body>Loaded</body><script>parent.postMessage(document.referrer, "*");</script></html>'
+ );
+}
diff --git a/dom/base/test/referrer_helper.js b/dom/base/test/referrer_helper.js
new file mode 100644
index 0000000000..e2e3e32835
--- /dev/null
+++ b/dom/base/test/referrer_helper.js
@@ -0,0 +1,133 @@
+// This helper expects these globals to be defined.
+/* global PARAMS, SJS, testCases */
+
+/*
+ * common functionality for iframe, anchor, and area referrer attribute tests
+ */
+const GET_RESULT = SJS + "ACTION=get-test-results";
+const RESET_STATE = SJS + "ACTION=resetState";
+
+SimpleTest.waitForExplicitFinish();
+var advance = function () {
+ tests.next();
+};
+
+/**
+ * Listen for notifications from the child.
+ * These are sent in case of error, or when the loads we await have completed.
+ */
+window.addEventListener("message", function (event) {
+ if (event.data == "childLoadComplete") {
+ // all loads happen, continue the test.
+ advance();
+ }
+});
+
+/**
+ * helper to perform an XHR
+ * to do checkIndividualResults and resetState
+ */
+function doXHR(aUrl, onSuccess, onFail) {
+ // The server is at http[s]://example.com so we need cross-origin XHR.
+ var xhr = new XMLHttpRequest({ mozSystem: true });
+ xhr.responseType = "json";
+ xhr.onload = function () {
+ onSuccess(xhr);
+ };
+ xhr.onerror = function () {
+ onFail(xhr);
+ };
+ xhr.open("GET", "http" + aUrl, true);
+ xhr.send(null);
+}
+
+/**
+ * Grabs the results via XHR and passes to checker.
+ */
+function checkIndividualResults(aTestname, aExpectedReferrer, aName) {
+ var onload = xhr => {
+ var results = xhr.response;
+ info(JSON.stringify(xhr.response));
+ ok(aName in results, aName + " tests have to be performed.");
+ is(
+ results[aName].policy,
+ aExpectedReferrer,
+ aTestname +
+ " --- " +
+ results[aName].policy +
+ " (" +
+ results[aName].referrer +
+ ")"
+ );
+ advance();
+ };
+ var onerror = xhr => {
+ ok(false, "Can't get results from the counter server.");
+ SimpleTest.finish();
+ };
+ doXHR(GET_RESULT, onload, onerror);
+}
+
+function resetState() {
+ doXHR(RESET_STATE, advance, function (xhr) {
+ ok(false, "error in reset state");
+ SimpleTest.finish();
+ });
+}
+
+/**
+ * testing if referrer header is sent correctly
+ */
+var tests = (function* () {
+ yield SpecialPowers.pushPrefEnv(
+ { set: [["network.preload", true]] },
+ advance
+ );
+ yield SpecialPowers.pushPrefEnv(
+ { set: [["security.mixed_content.block_active_content", false]] },
+ advance
+ );
+ yield SpecialPowers.pushPrefEnv(
+ { set: [["network.http.referer.disallowRelaxingDefault", false]] },
+ advance
+ );
+ yield SpecialPowers.pushPermissions(
+ [{ type: "systemXHR", allow: true, context: document }],
+ advance
+ );
+
+ var iframe = document.getElementById("testframe");
+
+ for (var j = 0; j < testCases.length; j++) {
+ if (testCases[j].PREFS) {
+ yield SpecialPowers.pushPrefEnv({ set: testCases[j].PREFS }, advance);
+ }
+
+ var actions = testCases[j].ACTION;
+ var subTests = testCases[j].TESTS;
+ for (var k = 0; k < actions.length; k++) {
+ var actionString = actions[k];
+ for (var i = 0; i < subTests.length; i++) {
+ yield resetState();
+ var searchParams = new URLSearchParams();
+ searchParams.append("ACTION", actionString);
+ searchParams.append("NAME", subTests[i].NAME);
+ for (var l of PARAMS) {
+ if (subTests[i][l]) {
+ searchParams.append(l, subTests[i][l]);
+ }
+ }
+ var schemeFrom = subTests[i].SCHEME_FROM || "http";
+ yield (iframe.src = schemeFrom + SJS + searchParams.toString());
+ yield checkIndividualResults(
+ subTests[i].DESC,
+ subTests[i].RESULT,
+ subTests[i].NAME
+ );
+ }
+ }
+ }
+
+ // complete.
+ SimpleTest.finish();
+})();
diff --git a/dom/base/test/referrer_testserver.sjs b/dom/base/test/referrer_testserver.sjs
new file mode 100644
index 0000000000..bb7acbc3b2
--- /dev/null
+++ b/dom/base/test/referrer_testserver.sjs
@@ -0,0 +1,693 @@
+/*
+ * Test server for iframe, anchor, and area referrer attributes.
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
+ * Also server for further referrer tests such as redirecting tests
+ * bug 1174913, bug 1175736, bug 1184781
+ */
+
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+const SJS = "referrer_testserver.sjs?";
+const SJS_PATH = "/tests/dom/base/test/";
+const BASE_ORIGIN = "example.com";
+const BASE_URL = BASE_ORIGIN + SJS_PATH + SJS;
+const SHARED_KEY = SJS;
+const SAME_ORIGIN = "mochi.test:8888" + SJS_PATH + SJS;
+const CROSS_ORIGIN_URL = "test1.example.com" + SJS_PATH + SJS;
+
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+function createTestUrl(
+ aPolicy,
+ aAction,
+ aName,
+ aType,
+ aSchemeFrom,
+ aSchemeTo,
+ crossOrigin,
+ referrerPolicyHeader
+) {
+ var schemeTo = aSchemeTo || "http";
+ var schemeFrom = aSchemeFrom || "http";
+ var rpHeader = referrerPolicyHeader || "";
+ var url = schemeTo + "://";
+ url += crossOrigin ? CROSS_ORIGIN_URL : BASE_URL;
+ url +=
+ "ACTION=" +
+ aAction +
+ "&" +
+ "policy=" +
+ aPolicy +
+ "&" +
+ "NAME=" +
+ aName +
+ "&" +
+ "type=" +
+ aType +
+ "&" +
+ "RP_HEADER=" +
+ rpHeader +
+ "&" +
+ "SCHEME_FROM=" +
+ schemeFrom;
+ return url;
+}
+
+// test page using iframe referrer attribute
+// if aParams are set this creates a test where the iframe url is a redirect
+function createIframeTestPageUsingRefferer(
+ aMetaPolicy,
+ aAttributePolicy,
+ aNewAttributePolicy,
+ aName,
+ aParams,
+ aSchemeFrom,
+ aSchemeTo,
+ aChangingMethod
+) {
+ var metaString = "";
+ if (aMetaPolicy) {
+ metaString = `<meta name="referrer" content="${aMetaPolicy}">`;
+ }
+ var changeString = "";
+ if (aChangingMethod === "setAttribute") {
+ changeString = `document.getElementById("myframe").setAttribute("referrerpolicy", "${aNewAttributePolicy}")`;
+ } else if (aChangingMethod === "property") {
+ changeString = `document.getElementById("myframe").referrerPolicy = "${aNewAttributePolicy}"`;
+ }
+ var iFrameString = `<iframe src="" id="myframe" ${
+ aAttributePolicy ? ` referrerpolicy="${aAttributePolicy}"` : ""
+ }>iframe</iframe>`;
+ var iframeUrl = "";
+ if (aParams) {
+ aParams.delete("ACTION");
+ aParams.append("ACTION", "redirectIframe");
+ iframeUrl = "http://" + CROSS_ORIGIN_URL + aParams.toString();
+ } else {
+ iframeUrl = createTestUrl(
+ aAttributePolicy,
+ "test",
+ aName,
+ "iframe",
+ aSchemeFrom,
+ aSchemeTo
+ );
+ }
+
+ return `<!DOCTYPE HTML>
+ <html>
+ <head>
+ ${metaString}
+ </head>
+ <body>
+ ${iFrameString}
+ <script>
+ window.addEventListener("load", function() {
+ ${changeString}
+ document.getElementById("myframe").onload = function(){
+ parent.postMessage("childLoadComplete", "http://mochi.test:8888");
+ };
+ document.getElementById("myframe").src = "${iframeUrl}";
+ }.bind(window), false);
+ </script>
+ </body>
+ </html>`;
+}
+
+function buildAnchorString(
+ aMetaPolicy,
+ aReferrerPolicy,
+ aName,
+ aRelString,
+ aSchemeFrom,
+ aSchemeTo
+) {
+ if (aReferrerPolicy) {
+ return `<a href="${createTestUrl(
+ aReferrerPolicy,
+ "test",
+ aName,
+ "link",
+ aSchemeFrom,
+ aSchemeTo
+ )}" referrerpolicy="${aReferrerPolicy}" id="link" ${aRelString}>${aReferrerPolicy}</a>`;
+ }
+ return `<a href="${createTestUrl(
+ aMetaPolicy,
+ "test",
+ aName,
+ "link",
+ aSchemeFrom,
+ aSchemeTo
+ )}" id="link" ${aRelString}>link</a>`;
+}
+
+function buildAreaString(
+ aMetaPolicy,
+ aReferrerPolicy,
+ aName,
+ aRelString,
+ aSchemeFrom,
+ aSchemeTo
+) {
+ var result = `<img src="file_mozfiledataurl_img.jpg" alt="image" usemap="#imageMap">`;
+ result += `<map name="imageMap">`;
+ if (aReferrerPolicy) {
+ result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(
+ aReferrerPolicy,
+ "test",
+ aName,
+ "link",
+ aSchemeFrom,
+ aSchemeTo
+ )}" alt="theArea" referrerpolicy="${aReferrerPolicy}" id="link" ${aRelString}>`;
+ } else {
+ result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(
+ aMetaPolicy,
+ "test",
+ aName,
+ "link",
+ aSchemeFrom,
+ aSchemeTo
+ )}" alt="theArea" id="link" ${aRelString}>`;
+ }
+ result += `</map>`;
+
+ return result;
+}
+
+// test page using anchor or area referrer attribute
+function createAETestPageUsingRefferer(
+ aMetaPolicy,
+ aAttributePolicy,
+ aNewAttributePolicy,
+ aName,
+ aRel,
+ aStringBuilder,
+ aSchemeFrom,
+ aSchemeTo,
+ aChangingMethod
+) {
+ var metaString = "";
+ if (aMetaPolicy) {
+ metaString = `<head><meta name="referrer" content="${aMetaPolicy}"></head>`;
+ }
+ var changeString = "";
+ if (aChangingMethod === "setAttribute") {
+ changeString = `document.getElementById("link").setAttribute("referrerpolicy", "${aNewAttributePolicy}")`;
+ } else if (aChangingMethod === "property") {
+ changeString = `document.getElementById("link").referrerPolicy = "${aNewAttributePolicy}"`;
+ }
+ var relString = "";
+ if (aRel) {
+ relString = `rel="noreferrer"`;
+ }
+ var elementString = aStringBuilder(
+ aMetaPolicy,
+ aAttributePolicy,
+ aName,
+ relString,
+ aSchemeFrom,
+ aSchemeTo
+ );
+
+ return `<!DOCTYPE HTML>
+ <html>
+ ${metaString}
+ <body>
+ ${elementString}
+ <script>
+ window.addEventListener("load", function() {
+ ${changeString}
+ document.getElementById("link").click();
+ }.bind(window), false);
+ </script>
+ </body>
+ </html>`;
+}
+
+// test page using anchor target=_blank rel=noopener
+function createTargetBlankRefferer(
+ aMetaPolicy,
+ aName,
+ aSchemeFrom,
+ aSchemeTo,
+ aRpHeader
+) {
+ var metaString = "";
+ if (aMetaPolicy) {
+ metaString = `<head><meta name="referrer" content="${aMetaPolicy}"></head>`;
+ }
+ var elementString = `<a href="${createTestUrl(
+ aMetaPolicy,
+ "test",
+ aName,
+ "link",
+ aSchemeFrom,
+ aSchemeTo,
+ aRpHeader
+ )}" target=_blank rel="noopener" id="link">link</a>`;
+
+ return `<!DOCTYPE HTML>
+ <html>
+ ${metaString}
+ <body>
+ ${elementString}
+ <script>
+ window.addEventListener("load", function() {
+ let link = document.getElementById("link");
+ SpecialPowers.wrap(window).parent.postMessage("childLoadReady", "*");
+ link.click();
+ }.bind(window), false);
+ </script>
+ </body>
+ </html>`;
+}
+
+// creates test page with img that is a redirect
+function createRedirectImgTestCase(aParams, aAttributePolicy) {
+ var metaString = "";
+ if (aParams.has("META_POLICY")) {
+ metaString = `<meta name="referrer" content="${aParams.get(
+ "META_POLICY"
+ )}">`;
+ }
+ aParams.delete("ACTION");
+ aParams.append("ACTION", "redirectImg");
+ var imgUrl = "http://" + CROSS_ORIGIN_URL + aParams.toString();
+
+ return `<!DOCTYPE HTML>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ ${metaString}
+ <title>Test referrer policies on redirect (img)</title>
+ </head>
+ <body>
+ <img id="testImg" src="${imgUrl}" ${
+ aAttributePolicy ? ` referrerpolicy="${aAttributePolicy}"` : ""
+ }>
+ <script>
+ window.addEventListener("load", function() {
+ parent.postMessage("childLoadComplete", "http://mochi.test:8888");
+ }.bind(window), false);
+ </script>
+ </body>
+ </html>`;
+}
+
+// test page using link referrer attribute
+function createLinkPageUsingRefferer(
+ aMetaPolicy,
+ aAttributePolicy,
+ aNewAttributePolicy,
+ aName,
+ aRel,
+ aStringBuilder,
+ aSchemeFrom,
+ aSchemeTo,
+ aTestType
+) {
+ var metaString = "";
+ if (aMetaPolicy) {
+ metaString = `<meta name="referrer" content="${aMetaPolicy}">`;
+ }
+
+ var changeString = "";
+ var policy = aAttributePolicy ? aAttributePolicy : aMetaPolicy;
+ var elementString = aStringBuilder(
+ policy,
+ aName,
+ aRel,
+ aSchemeFrom,
+ aSchemeTo,
+ aTestType
+ );
+
+ if (aTestType === "setAttribute") {
+ changeString = `var link = document.getElementById("test_link");
+ link.setAttribute("referrerpolicy", "${aNewAttributePolicy}");
+ link.href = "${createTestUrl(
+ policy,
+ "test",
+ aName,
+ "link_element_" + aRel,
+ aSchemeFrom,
+ aSchemeTo
+ )}";`;
+ } else if (aTestType === "property") {
+ changeString = `var link = document.getElementById("test_link");
+ link.referrerPolicy = "${aNewAttributePolicy}";
+ link.href = "${createTestUrl(
+ policy,
+ "test",
+ aName,
+ "link_element_" + aRel,
+ aSchemeFrom,
+ aSchemeTo
+ )}";`;
+ }
+
+ return `<!DOCTYPE HTML>
+ <html>
+ <head>
+ ${metaString}
+ </head>
+ <body>
+ ${elementString}
+ <script>
+ ${changeString}
+ </script>
+ </body>
+ </html>`;
+}
+
+function createFetchUserControlRPTestCase(
+ aName,
+ aSchemeFrom,
+ aSchemeTo,
+ crossOrigin
+) {
+ var srcUrl = createTestUrl(
+ "",
+ "test",
+ aName,
+ "fetch",
+ aSchemeFrom,
+ aSchemeTo,
+ crossOrigin
+ );
+
+ return `<!DOCTYPE HTML>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <title>Test user control referrer policies</title>
+ </head>
+ <body>
+ <script>
+ fetch("${srcUrl}", {referrerPolicy: ""}).then(function (response) {
+ window.parent.postMessage("childLoadComplete", "http://mochi.test:8888");
+ });
+ </script>
+ </body>
+ </html>`;
+}
+
+function buildLinkString(
+ aPolicy,
+ aName,
+ aRel,
+ aSchemeFrom,
+ aSchemeTo,
+ aTestType
+) {
+ var href = "";
+ var onChildComplete = `window.parent.postMessage("childLoadComplete", "http://mochi.test:8888");`;
+ var policy = "";
+ var asString = "";
+ var relString = "";
+
+ if (aRel) {
+ relString = `rel="${aRel}"`;
+ }
+
+ if (aPolicy) {
+ policy = `referrerpolicy=${aPolicy}`;
+ }
+
+ if (aRel == "preload") {
+ asString = 'as="image"';
+ }
+
+ if (!aTestType) {
+ href = `href=${createTestUrl(
+ aPolicy,
+ "test",
+ aName,
+ "link_element_" + aRel,
+ aSchemeFrom,
+ aSchemeTo
+ )}`;
+ }
+
+ return `<link ${relString} ${href} ${policy} ${asString} id="test_link" onload='${onChildComplete}' onerror='${onChildComplete}'>`;
+}
+
+// eslint-disable-next-line complexity
+function handleRequest(request, response) {
+ var params = new URLSearchParams(request.queryString);
+ var action = params.get("ACTION");
+ var schemeFrom = params.get("SCHEME_FROM") || "http";
+ var schemeTo = params.get("SCHEME_TO") || "http";
+ var crossOrigin = params.get("CROSS_ORIGIN") || false;
+ var referrerPolicyHeader = params.get("RP_HEADER") || "";
+
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+ if (referrerPolicyHeader) {
+ response.setHeader("Referrer-Policy", referrerPolicyHeader, false);
+ }
+
+ if (action === "resetState") {
+ setSharedState(SHARED_KEY, "{}");
+ response.write("");
+ return;
+ }
+ if (action === "get-test-results") {
+ // ?action=get-result
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(getSharedState(SHARED_KEY));
+ return;
+ }
+ if (action === "redirect") {
+ response.write(
+ '<script>parent.postMessage("childLoadComplete", "http://mochi.test:8888");</script>'
+ );
+ return;
+ }
+ if (action === "redirectImg") {
+ params.delete("ACTION");
+ params.append("ACTION", "test");
+ params.append("type", "img");
+ // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect
+ response.setStatusLine("1.1", 302, "found");
+ response.setHeader(
+ "Location",
+ "http://" + CROSS_ORIGIN_URL + params.toString(),
+ false
+ );
+ return;
+ }
+ if (action === "redirectIframe") {
+ params.delete("ACTION");
+ params.append("ACTION", "test");
+ params.append("type", "iframe");
+ // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect
+ response.setStatusLine("1.1", 302, "found");
+ response.setHeader(
+ "Location",
+ "http://" + CROSS_ORIGIN_URL + params.toString(),
+ false
+ );
+ return;
+ }
+ if (action === "test") {
+ // ?action=test&policy=origin&name=name
+ var policy = params.get("policy");
+ var name = params.get("NAME");
+ var type = params.get("type");
+ var result = getSharedState(SHARED_KEY);
+
+ result = result ? JSON.parse(result) : {};
+
+ var referrerLevel = "none";
+ var test = {};
+ if (request.hasHeader("Referer")) {
+ var referrer = request.getHeader("Referer");
+ if (referrer.indexOf("referrer_testserver") > 0) {
+ referrerLevel = "full";
+ } else if (referrer.indexOf(schemeFrom + "://example.com") == 0) {
+ referrerLevel = "origin";
+ } else {
+ // this is never supposed to happen
+ referrerLevel = "other-origin";
+ }
+ test.referrer = referrer;
+ } else {
+ test.referrer = "";
+ }
+ test.policy = referrerLevel;
+ test.expected = policy;
+
+ result[name] = test;
+
+ setSharedState(SHARED_KEY, JSON.stringify(result));
+
+ if (type === "img" || type == "link_element_preload") {
+ // return image
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+ if (type === "iframe") {
+ // return iframe page
+ response.write("<html><body>I am the iframe</body></html>");
+ return;
+ }
+ if (type === "link") {
+ // forward link click to redirect URL to finish test
+ var loc = "http://" + BASE_URL + "ACTION=redirect";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+ }
+ return;
+ }
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+
+ // parse test arguments and start test
+ var attributePolicy = params.get("ATTRIBUTE_POLICY") || "";
+ var newAttributePolicy = params.get("NEW_ATTRIBUTE_POLICY") || "";
+ var metaPolicy = params.get("META_POLICY") || "";
+ var rel = params.get("REL") || "";
+ var name = params.get("NAME");
+
+ // anchor & area
+ var _getPage = createAETestPageUsingRefferer.bind(
+ null,
+ metaPolicy,
+ attributePolicy,
+ newAttributePolicy,
+ name,
+ rel
+ );
+ var _getAnchorPage = _getPage.bind(
+ null,
+ buildAnchorString,
+ schemeFrom,
+ schemeTo
+ );
+ var _getAreaPage = _getPage.bind(null, buildAreaString, schemeFrom, schemeTo);
+
+ // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod, aStringBuilder
+ if (action === "generate-anchor-policy-test") {
+ response.write(_getAnchorPage());
+ return;
+ }
+ if (action === "generate-anchor-changing-policy-test-set-attribute") {
+ response.write(_getAnchorPage("setAttribute"));
+ return;
+ }
+ if (action === "generate-anchor-changing-policy-test-property") {
+ response.write(_getAnchorPage("property"));
+ return;
+ }
+ if (action === "generate-area-policy-test") {
+ response.write(_getAreaPage());
+ return;
+ }
+ if (action === "generate-area-changing-policy-test-set-attribute") {
+ response.write(_getAreaPage("setAttribute"));
+ return;
+ }
+ if (action === "generate-area-changing-policy-test-property") {
+ response.write(_getAreaPage("property"));
+ return;
+ }
+ if (action === "generate-anchor-target-blank-policy-test") {
+ response.write(
+ createTargetBlankRefferer(
+ metaPolicy,
+ name,
+ schemeFrom,
+ schemeTo,
+ referrerPolicyHeader
+ )
+ );
+ return;
+ }
+
+ // iframe
+ _getPage = createIframeTestPageUsingRefferer.bind(
+ null,
+ metaPolicy,
+ attributePolicy,
+ newAttributePolicy,
+ name,
+ "",
+ schemeFrom,
+ schemeTo
+ );
+
+ // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod
+ if (action === "generate-iframe-policy-test") {
+ response.write(_getPage());
+ return;
+ }
+ if (action === "generate-iframe-changing-policy-test-set-attribute") {
+ response.write(_getPage("setAttribute"));
+ return;
+ }
+ if (action === "generate-iframe-changing-policy-test-property") {
+ response.write(_getPage("property"));
+ return;
+ }
+
+ // redirect tests with img and iframe
+ if (action === "generate-img-redirect-policy-test") {
+ response.write(createRedirectImgTestCase(params, attributePolicy));
+ return;
+ }
+ if (action === "generate-iframe-redirect-policy-test") {
+ response.write(
+ createIframeTestPageUsingRefferer(
+ metaPolicy,
+ attributePolicy,
+ newAttributePolicy,
+ name,
+ params,
+ schemeFrom,
+ schemeTo
+ )
+ );
+ return;
+ }
+
+ var _getPage = createLinkPageUsingRefferer.bind(
+ null,
+ metaPolicy,
+ attributePolicy,
+ newAttributePolicy,
+ name,
+ rel
+ );
+ var _getLinkPage = _getPage.bind(null, buildLinkString, schemeFrom, schemeTo);
+
+ // link
+ if (action === "generate-link-policy-test") {
+ response.write(_getLinkPage());
+ return;
+ }
+ if (action === "generate-link-policy-test-set-attribute") {
+ response.write(_getLinkPage("setAttribute"));
+ return;
+ }
+ if (action === "generate-link-policy-test-property") {
+ response.write(_getLinkPage("property"));
+ return;
+ }
+
+ if (action === "generate-fetch-user-control-policy-test") {
+ response.write(
+ createFetchUserControlRPTestCase(name, schemeFrom, schemeTo, crossOrigin)
+ );
+ return;
+ }
+
+ response.write("I don't know action " + action);
+ return;
+}
diff --git a/dom/base/test/reftest/mixed-bmp-png.ico b/dom/base/test/reftest/mixed-bmp-png.ico
new file mode 100644
index 0000000000..32e2c4995c
--- /dev/null
+++ b/dom/base/test/reftest/mixed-bmp-png.ico
Binary files differ
diff --git a/dom/base/test/reftest/reftest.list b/dom/base/test/reftest/reftest.list
new file mode 100644
index 0000000000..8aa3f3b949
--- /dev/null
+++ b/dom/base/test/reftest/reftest.list
@@ -0,0 +1,7 @@
+== test_bug920877.html test_bug920877-ref.html
+HTTP == test_xmlPrettyPrint_csp.xml test_xmlPrettyPrint_csp-ref.xml
+# Ordinarily, reftests use a browser.viewport.desktopWidth of 800px, same as the
+# size of the reftest document. This test however needs something more representative
+# of a real mobile device, where the desktop viewport width doesn't match the
+# width of the device screen.
+test-pref(dom.meta-viewport.enabled,true) test-pref(browser.viewport.desktopWidth,1200) == test_bug1525662.txt test_bug1525662-ref.html
diff --git a/dom/base/test/reftest/test_bug1525662-ref.html b/dom/base/test/reftest/test_bug1525662-ref.html
new file mode 100644
index 0000000000..063daf7615
--- /dev/null
+++ b/dom/base/test/reftest/test_bug1525662-ref.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<meta name="viewport" content="width=device-width">
+</head>
+<body>
+<pre style="white-space: pre-wrap; word-wrap: break-word">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/reftest/test_bug1525662.txt b/dom/base/test/reftest/test_bug1525662.txt
new file mode 100644
index 0000000000..33fd1fd851
--- /dev/null
+++ b/dom/base/test/reftest/test_bug1525662.txt
@@ -0,0 +1,7 @@
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
diff --git a/dom/base/test/reftest/test_bug920877-ref.html b/dom/base/test/reftest/test_bug920877-ref.html
new file mode 100644
index 0000000000..1a593e5849
--- /dev/null
+++ b/dom/base/test/reftest/test_bug920877-ref.html
@@ -0,0 +1,20 @@
+<html>
+<body>
+<script>
+var img = document.createElement("img");
+img.id = "img-ori";
+img.src = "mixed-bmp-png.ico";
+document.body.appendChild(img);
+
+img = document.createElement("img");
+img.id = "img-res32";
+img.src = "mixed-bmp-png.ico#-moz-resolution=32,32";
+document.body.appendChild(img);
+
+img = document.createElement("img");
+img.id = "img-res48";
+img.src = "mixed-bmp-png.ico#-moz-resolution=48,48";
+document.body.appendChild(img);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/reftest/test_bug920877.html b/dom/base/test/reftest/test_bug920877.html
new file mode 100644
index 0000000000..18bae4009e
--- /dev/null
+++ b/dom/base/test/reftest/test_bug920877.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+</head>
+<body>
+<script>
+var dataURL = "data:image/vnd.microsoft.icon;base64,AAABAAQAMDAAAAEAIACoJQAARgAAACAgAAABACAAqBAAAO4lAAAYGAAAAQAgAIgJAACWNgAAEBAAAAEAIABoBAAAHkAAACgAAAAwAAAAYAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmAEDQZgCA0GYAv9BmAN/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgDf0GYAv9BmAIDQZgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmAEDQZgCf0GYA79BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA79BmAJ/QZgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQZgBA0GYAv9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYAv9BmAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAINBmAK/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgCv0GYAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQZgBQ0GYA79BmAP/QZgD/0GYA/9BmAL/QZgC/0GYAv9BmAL/QZgC/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA79BmAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmAI/QZgDv0GYAn9BmAFDQZgAQAAAAAAAAAAAAAAAAIB8jECAfI0AgHyNAIB8jINBmABDQZgBA0GYAgNBmAK/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgCPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAgNBmAGAAAAAAAAAAAAAAAAAAAAAAIB8jQCAfI58gHyPvIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyPPIB8jjyAfIzAAAAAA0GYAUNBmAJ/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYAnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfIxAgHyO/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyPPIB8jYAAAAADQZgAQ0GYAcNBmAN/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAJ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jMCAfI+8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI78gHyNAAAAAAAAAAADQZgBg0GYA39BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgCPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMQIB8j7yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jjwAAAAAAAAAAAAAAANBmAIDQZgDv0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOfIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyOAIB8jgCAfI4AgHyOAIB8jgCAfI4AgHyOAIB8jgCAfI4AgHyOAIB8jgCAfI4AgHyOAIB8jgCAfI0AAAAAAAAAAAAAAAADQZgAg0GYAv9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA79BmACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfIyAgHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyNgIB8jEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmAHDQZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAK8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI48gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI68gHyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyNgIB8jzyAfIzAAAAAAAAAAAAAAAADQZgAw0GYA39BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI78gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jvyAfIyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jICAfI78gHyP/IB8j/yAfI+8gHyMwAAAAAAAAAAAAAAAA0GYAENBmAM/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgC/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI+8gHyMwAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyNQIB8j7yAfI/8gHyP/IB8j/yAfI/8gHyPvIB8jIAAAAAAAAAAAAAAAANBmABDQZgDP0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyPfIB8jEAAAAAAAAAAAAAAAACAfI2AgHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jzyAfIxAAAAAAAAAAAAAAAADQZgAQ0GYAz9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYAnwAAAAAAAAAAIhvgEAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jQCAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jzyAfI4AgHyNAIB8jgCAfI78gHyP/IB8jcAAAAAAAAAAAIB8jICAfI/8gHyPfIB8jcCAfI0AgHyNQIB8jjyAfI+8gHyP/IB8j/yAfI58AAAAAAAAAAAAAAAAAAAAA0GYAENBmAM/QZgD/0GYA/9BmAP/QZgD/0GYA7wAAAAAiG+BAIhvgQAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jMCAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI+8gHyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOfIB8jvwAAAAAAAAAAIB8jcCAfI88gHyMQAAAAAAAAAAAAAAAAAAAAACAfIxAgHyOfIB8j/yAfI/8gHyNQAAAAAAAAAAAAAAAAAAAAANBmACDQZgDv0GYA/9BmAP/QZgD/0GYA/9BmAEAiG+CAIhvgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j7yAfIzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMQIB8j3wAAAAAAAAAAIB8jgCAfI0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jnyAfI/8gHyPvIB8jEAAAAAAAAAAAAAAAAAAAAADQZgBA0GYA/9BmAP/QZgD/0GYA/9BmAIAiG+C/IhvgcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jjwAAAAAAAAAAIB8jYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI98gHyP/IB8jgAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAj9BmAP/QZgD/0GYA/9BmAL8iG+DfIhvgjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI78gHyP/IB8j/yAfI/8gHyPPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jEAAAAAAAAAAAIB8jEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI2AgHyP/IB8j7yAfIyAAAAAAAAAAAAAAAAAAAAAA0GYAENBmAN/QZgD/0GYA/9BmAN8iG+D/Ihvg3wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI58gHyP/IB8j/yAfI/8gHyOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfIxAgHyP/IB8j/yAfI4AAAAAAAAAAAAAAAAAAAAAAAAAAANBmAGDQZgD/0GYA/9BmAP8iG+D/Ihvg/yIb4CAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI2AgHyP/IB8j/yAfI/8gHyNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyP/IB8j/yAfI+8gHyMQAAAAAAAAAAAAAAAAAAAAAAAAAADQZgDf0GYA/9BmAP8iG+D/Ihvg/yIb4I8AAAAAAAAAAAAAAAAAAAAAAAAAACAfIxAgHyP/IB8j/yAfI/8gHyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyP/IB8j/yAfI/8gHyNgAAAAAAAAAAAAAAAAAAAAAAAAAADQZgBg0GYA/9BmAP8iG+D/Ihvg/yIb4O8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOvIB8j/yAfI/8gHyNwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyP/IB8j/yAfI/8gHyOvAAAAAAAAAAAAAAAAAAAAAAAAAADQZgAQ0GYA79BmAP8iG+D/Ihvg/yIb4P8iG+BwAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyNQIB8j/yAfI/8gHyOfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI0AgHyP/IB8j/yAfI/8gHyPvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAn9BmAP8iG+D/Ihvg/yIb4P8iG+DvIhvgEAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8j3yAfI/8gHyPvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI48gHyP/IB8j/yAfI/8gHyP/IB8jQAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAYNBmAP8iG+DfIhvg/yIb4P8iG+D/IhvgjwAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jYCAfI/8gHyP/IB8jYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI+8gHyP/IB8j/yAfI/8gHyP/IB8jcAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAINBmAN8iG+C/Ihvg/yIb4P8iG+D/Ihvg/yIb4EAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI98gHyP/IB8jvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jYCAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmAK8iG+CAIhvg/yIb4P8iG+D/Ihvg/yIb4N8iG+AQAAAAAAAAAAAAAAAAAAAAACAfI0AgHyP/IB8j/yAfI1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMQIB8j3yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmADAiG+BAIhvg/yIb4P8iG+D/Ihvg/yIb4P8iG+C/AAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOPIB8j/yAfI98gHyMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOAIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvg7yIb4P8iG+D/Ihvg/yIb4P8iG+D/IhvgnwAAAAAAAAAAAAAAAAAAAAAgHyMQIB8jzyAfI/8gHyOfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfIzAgHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgnyIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4J8AAAAAAAAAAAAAAAAAAAAAIB8jMCAfI+8gHyP/IB8jYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jECAfI98gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgQCIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+CfAAAAAAAAAAAAAAAAAAAAACAfI1AgHyP/IB8j/yAfIzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jvyAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4L8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/IhvgnwAAAAAAAAAAAAAAAAAAAAAgHyNgIB8j/yAfI+8gHyMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOfIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4EAiG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4M8iG+AgAAAAAAAAAAAAAAAAIB8jYCAfI/8gHyPvIB8jMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI58gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+CvIhvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+DvIhvgUAAAAAAAAAAAAAAAACAfI1AgHyPvIB8j7yAfI1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMQIB8jnyAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyOfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+AgIhvg7yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4K8iG+AQAAAAAAAAAAAgHyMwIB8jzyAfI/8gHyNwAAAAAAAAAAAAAAAAAAAAACAfIxAgHyPPIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgUCIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+DvIhvgcAAAAAAAAAAAIB8jECAfI48gHyP/IB8jnyAfIxAAAAAAIB8jMCAfI98gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4I8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4N8iG+BgAAAAAAAAAAAgHyNAIB8jvyAfI88gHyOAIB8j7yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+CfIhvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg7yIb4IAiG+AgAAAAACAfI2AgHyO/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgnyIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/IhvgzyIb4HAiG+AgIB8jICAfI4AgHyO/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyPPIB8jjyAfIyAAAAAAAAAAAAAAAAAiG+AwIhvgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4I8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg3yIb4K8iG+CAIhvgQCIb4DAgHyNAIB8jIAAAAAAAAAAAAAAAACIb4DAiG+BQIhvgjyIb4M8iG+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+BQIhvg7yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg7yIb4FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgICIb4K8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+CvIhvgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+BAIhvgvyIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/IhvgvyIb4EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4EAiG+CfIhvg7yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg7yIb4J8iG+AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4EAiG+CAIhvgvyIb4N8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+DfIhvgvyIb4IAiG+BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//4AB//+nbP/8AAA//6ds//AAAA//p2z/wAAAA/+nbP+AAAAB/6ds/wcAAAD/p2z+eACAAH+nbP/gACAAP6ds/8AADAAfp2z/gAAHAA+nbP+AAAOAB6ds/wB//+AHp2z/AB/8cAOnbP8AB/A4A6ds/wAD4BwBp2z/AAHADgGnbL4AAYAPAadsPgD5jweAp2w/Afmfw8CnbD8D/b/j4KdsPwf9v+Hgp2w/B///4fCnbB8H///w+KdsHwf///D4p2wfh///8PinbA+H///g/KdsB8f//+B8p2wHw///4HynbAPj///AfqdsAeH//4B+p2wB8P//gH+nbIDw//8Af6dsgHh//gB/p2yAPD/+AH+nbMAeH/wAf6dswAcP+AB/p2zgA4fgAP+nbOAAw8AA/6ds8ABggAH/p2z4ABgAA/+nbPwAAgAH/6ds/gAAAA5/p2z/AAAA4P+nbP+AAAAB/6ds/8AAAAP/p2z/8AAAD/+nbP/8AAA//6ds//+AAf//p2woAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmADDQZgCA0GYAv9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAL/QZgCA0GYAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmAFDQZgDP0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYAz9BmAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmACDQZgC/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAL/QZgAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQZgBQ0GYA39BmAJ/QZgBw0GYAQNBmAECFSA9weEMSgNBmAHDQZgCP0GYAz9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAO/QZgBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAINBmAGAAAAAAAAAAACAfI1AgHyO/IB8j/yAfI/8gHyP/IB8j/yAfI98gHyOPZjsVUNBmAHDQZgDP0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOfIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jryAfIyDQZgBA0GYAv9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jgCAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j7yAfI2AAAAAA0GYAQNBmAN/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAO/QZgAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfIyAgHyP/IB8j/yAfI/8gHyP/IB8jUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAENBmAI/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAL8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jcCAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j3yAfI4AgHyMQAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMgIB8jvyAfI58AAAAAAAAAANBmAFDQZgDv0GYA/9BmAP/QZgD/0GYA/9BmAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOvIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI88gHyMQAAAAAAAAAAAAAAAAIB8jYCAfI+8gHyP/IB8j/yAfI58AAAAAAAAAANBmADDQZgDv0GYA/9BmAP/QZgD/0GYAzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI78gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI78AAAAAAAAAACAfI4AgHyP/IB8j/yAfI/8gHyP/IB8j/yAfI3AAAAAAAAAAANBmADDQZgDv0GYA/9BmAP/QZgD/0GYAMCIb4EAAAAAAAAAAAAAAAAAAAAAAIB8jvyAfI/8gHyP/IB8j/yAfI/8gHyOAIB8jEAAAAAAgHyMwIB8j3yAfIzAAAAAAIB8j3yAfI0AAAAAAAAAAACAfI1AgHyPfIB8j/yAfIzAAAAAAAAAAANBmAEDQZgD/0GYA/9BmAP/QZgCAIhvgvwAAAAAAAAAAAAAAAAAAAAAgHyO/IB8j/yAfI/8gHyP/IB8jYAAAAAAAAAAAAAAAAAAAAAAgHyNAIB8jQAAAAAAgHyOAAAAAAAAAAAAAAAAAAAAAACAfIxAgHyPvIB8jzwAAAAAAAAAAAAAAANBmAIDQZgD/0GYA/9BmAL8iG+D/IhvgEAAAAAAAAAAAAAAAACAfI58gHyP/IB8j/yAfI58AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMgAAAAACAfIyAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI2AgHyP/IB8jYAAAAAAAAAAAAAAAANBmAM/QZgD/0GYA/yIb4P8iG+BQAAAAAAAAAAAAAAAAIB8jcCAfI/8gHyP/IB8jUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jECAfI/8gHyPfAAAAAAAAAAAAAAAA0GYAQNBmAP/QZgD/Ihvg/yIb4K8AAAAAAAAAAAAAAAAgHyMgIB8j/yAfI/8gHyNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8j/yAfI/8gHyMwAAAAAAAAAAAAAAAA0GYAv9BmAP8iG+D/Ihvg/yIb4CAAAAAAAAAAAAAAAAAgHyPPIB8j/yAfI2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfIxAgHyP/IB8j/yAfI48AAAAAAAAAAAAAAADQZgBQ0GYA/yIb4P8iG+D/IhvgnwAAAAAAAAAAAAAAACAfI2AgHyP/IB8jnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jYCAfI/8gHyP/IB8jzwAAAAAAAAAAAAAAAAAAAADQZgD/Ihvg/yIb4P8iG+D/IhvgQAAAAAAAAAAAAAAAACAfI98gHyPvIB8jEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyO/IB8j/yAfI/8gHyP/AAAAAAAAAAAAAAAAAAAAANBmAL8iG+C/Ihvg/yIb4P8iG+DfIhvgEAAAAAAAAAAAIB8jUCAfI/8gHyOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jQCAfI/8gHyP/IB8j/yAfI/8gHyMQAAAAAAAAAAAAAAAA0GYAQCIb4IAiG+D/Ihvg/yIb4P8iG+CvAAAAAAAAAAAAAAAAIB8jryAfI/8gHyMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyPPIB8j/yAfI/8gHyP/IB8j/yAfI0AAAAAAAAAAAAAAAAAAAAAAIhvgMCIb4P8iG+D/Ihvg/yIb4P8iG+CfAAAAAAAAAAAgHyMQIB8j3yAfI88gHyMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jjyAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jIAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgzyIb4P8iG+D/Ihvg/yIb4P8iG+CfAAAAAAAAAAAgHyMwIB8j7yAfI68AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI2AgHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+BgIhvg/yIb4P8iG+D/Ihvg/yIb4P8iG+C/IhvgEAAAAAAgHyMwIB8j7yAfI58AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyNgIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+C/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+DvIhvgQAAAAAAgHyMwIB8j3yAfI78gHyMQAAAAAAAAAAAAAAAAIB8jYCAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4CAiG+DvIhvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/IhvgryIb4CAgHyMQIB8jryAfI88gHyMwAAAAACAfI58gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8jzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4FAiG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4J8iG+AgIB8jUCAfI88gHyPPIB8j/yAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI98gHyMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4GAiG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+C/IhvgYCEeWXAgHyOvIB8j7yAfI/8gHyP/IB8j/yAfI98gHyOAIB8jEAAAAAAiG+AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4FAiG+DvIhvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4N8iG+CvIhvggCEcm68iG+BAIhvgYCIb4IAiG+CfIhvgzyIb4FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4CAiG+C/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4L8iG+AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+BgIhvgzyIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4M8iG+BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgMCIb4IAiG+C/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/IhvgvyIb4IAiG+AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AA///AAD//AAAP/gAAB/zAAAP/gAAB/wACAP4H/wD+APjAfgBwYH4AYDAeAiYYHg8vHA4fr44OH/+ODh//xwcf/4cHH/+Hg4//h4GP/wOBx/8DwMP+A+Bj/AfgEfgH8AhwB/AAIA/4AAAP/AAAF/4AAAf/AAAP/8AAP//wAP/KAAAABgAAAAwAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQZgBQ0GYAn9BmAN/QZgD/0GYA/9BmAP/QZgD/0GYA39BmAJ/QZgBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAQNBmAN/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA39BmAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQZgCP0GYAz9BmAI/QZgCAoFMKr6BTCq/QZgCv0GYA39BmAP/QZgD/0GYA/9BmAP/QZgD/0GYA/9BmAP/QZgCPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANBmADDQZgAgIB8jECAfI58gHyPvIB8j/yAfI/8gHyP/IB8jz0wxGoDQZgCA0GYA39BmAP/QZgD/0GYA/9BmAP/QZgD/0GYAnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMQIB8jzyAfI/8gHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyPPIB8jMNBmAGDQZgDv0GYA/9BmAP/QZgD/0GYA/9BmAI8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOAIB8j/yAfI/8gHyO/IB8jUCAfI0AgHyNAIB8jQCAfI0AgHyNAIB8jMAAAAADQZgAQ0GYAr9BmAP/QZgD/0GYA/9BmAP/QZgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyPvIB8j/yAfI/8gHyP/IB8j/yAfI58gHyMQAAAAAAAAAAAAAAAAIB8jUCAfI98gHyNgAAAAANBmAGDQZgD/0GYA/9BmAP/QZgDfAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyP/IB8j/yAfI/8gHyP/IB8j/yAfI/8gHyPPIB8jEAAAAAAgHyOPIB8j/yAfI/8gHyP/IB8jYAAAAADQZgBg0GYA/9BmAP/QZgD/0GYAUCIb4FAAAAAAAAAAACAfI0AgHyP/IB8j/yAfI/8gHyPfIB8jYCAfI0AgHyOvIB8jYCAfIzAgHyPPIB8jQCAfI1AgHyO/IB8j7yAfIyAAAAAA0GYAYNBmAP/QZgD/0GYAnyIb4J8AAAAAAAAAAAAAAAAgHyP/IB8j/yAfI98gHyMQAAAAAAAAAAAgHyMQIB8jcCAfI0AgHyMgAAAAAAAAAAAAAAAAIB8jryAfI78AAAAAAAAAANBmAI/QZgD/0GYA3yIb4O8AAAAAAAAAAAAAAAAgHyPvIB8j/yAfI2AAAAAAAAAAAAAAAAAAAAAAIB8jECAfIxAAAAAAAAAAAAAAAAAAAAAAIB8jMCAfI/8gHyNAAAAAANBmABDQZgDf0GYA/yIb4P8iG+BAAAAAAAAAAAAgHyOvIB8j/yAfI0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI/8gHyOfAAAAAAAAAADQZgBg0GYA/yIb4P8iG+CvAAAAAAAAAAAgHyNgIB8j/yAfI1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jICAfI/8gHyP/AAAAAAAAAADQZgAQ0GYA7yIb4P8iG+D/IhvgQAAAAAAAAAAAIB8j3yAfI58AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jcCAfI/8gHyP/IB8jQAAAAAAAAAAA0GYAryIb4N8iG+D/Ihvg3yIb4BAAAAAAIB8jYCAfI/8gHyMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMQIB8j3yAfI/8gHyP/IB8jUAAAAAAAAAAA0GYAYCIb4J8iG+D/Ihvg/yIb4K8AAAAAAAAAACAfI78gHyO/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyOAIB8j/yAfI/8gHyP/IB8jgAAAAAAAAAAAAAAAACIb4FAiG+D/Ihvg/yIb4P8iG+CfAAAAACAfIxAgHyPfIB8jgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI1AgHyP/IB8j/yAfI/8gHyP/IB8jQAAAAAAAAAAAAAAAAAAAAAAiG+DfIhvg/yIb4P8iG+D/IhvgryIb4BAgHyMwIB8j7yAfI2AAAAAAAAAAAAAAAAAAAAAAIB8jMCAfI+8gHyP/IB8j/yAfI/8gHyP/IB8jMAAAAAAAAAAAAAAAAAAAAAAiG+BAIhvg/yIb4P8iG+D/Ihvg/yIb4N8iG+BAIB8jICAfI88gHyOPAAAAAAAAAAAgHyNgIB8j7yAfI/8gHyP/IB8j/yAfI/8gHyO/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgjyIb4P8iG+D/Ihvg/yIb4P8iG+D/IhvgryEcoTAgHyOPIB8jvyAfI4AgHyP/IB8j/yAfI/8gHyP/IB8j/yAfI+8gHyMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIb4J8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+C/IhyxgCAfNp8gHyPfIB8j/yAfI/8gHyP/IB8jvyAfIzAiG+AgIhvgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+CPIhvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+DfIhvgvyEcrK8iG+CAIhvgnyIb4M8iG+CPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvgQCIb4N8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg/yIb4P8iG+D/Ihvg3yIb4EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiG+BQIhvgnyIb4N8iG+D/Ihvg/yIb4P8iG+D/Ihvg3yIb4J8iG+BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4Af0H4AB9B8AAPQeAAB0HwAANB8AEBQfAcQUHwCCBBYAAQQXDDmEFx54hBMf/MQTH/jEEZ/4ZBCP8GQQz/B0EEfgdBgDwHQYAYD0HAAA9B4AAHQfAAD0H4AB9B/gB/QSgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0GYAQNBmAKXQZgDm0GYA/9BmAP/QZgDm0GYApdBmAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQZgAQ0GYAjNBmAKWkVAieqFYHr9BmANPQZgD/0GYA/9BmAP/QZgD/0GYArNBmABAAAAAAAAAAAAAAAAAAAAAA0GYAGSAfIyIgHyO8IB8j/SAfI/8gHyPWUjMZirZbBIPQZgDq0GYA/9BmAP/QZgDN0GYAEAAAAAAAAAAAAAAAACAfIwQgHyPYIB8j/yAfI4wgHyOAIB8jgCAfI4AgHyNQ0GYADtBmAJXQZgD/0GYA/9BmAKwAAAAAAAAAAAAAAAAgHyNBIB8j/yAfI/8gHyP2IB8jjyAfIwUAAAAAIB8jWSAfI88gHyMj0GYAVdBmAPrQZgD/0GYAQCIb3xAAAAAAIB8jYSAfI/8gHyP9IB8jniAfI4AgHyNqIB8jTiAfI4MgHyOKIB8jyiAfIwnQZgBR0GYA/dBmAKUiG99gAAAAACAfI04gHyP/IB8jeAAAAAAAAAAAIB8jLCAfIyIAAAAAAAAAACAfI1EgHyOBAAAAANBmAIfQZgDmIhvfugAAAAAgHyMeIB8j/yAfIx4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgHyMCIB8j7yAfIwzQZgAL0GYA6iIb3/0iG98pAAAAACAfI8MgHyM5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIB8jFyAfI/8gHyNRAAAAANBmAI4iG9/mIhvfvSIb3wIgHyNHIB8jmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAfI3ggHyP/IB8jgQAAAADQZgA1IhvfpSIb3/8iG9+OAAAAACAfI5ogHyM6AAAAAAAAAAAAAAAAAAAAACAfIyAgHyPxIB8j/yAfI44AAAAAAAAAACIb30AiG9//Ihvf/yIb348hHIEMIB8jpyAfIyUAAAAAAAAAACAfIxIgHyPRIB8j/yAfI/8gHyNsAAAAAAAAAAAAAAAAIhvfrCIb3/8iG9//IhvfxSEbsDIgHyOIIB8jPCAfIyAgHyPUIB8j/yAfI/8gHyPxIB8jFQAAAAAAAAAAAAAAACIb3xAiG9/NIhvf/yIb3/8iG9/7IhvfpSEdgYEgHjioIB8j+CAfI/8gHyPUIB8jPCIb3wkAAAAAAAAAAAAAAAAAAAAAIhvfECIb36wiG9//Ihvf/yIb3/8iG9//Ihvf8yIb38UhHLC1IhvfryIb34UiG98OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhvfQCIb36UiG9/mIhvf/yIb3/8iG9/mIhvfpSIb3z4AAAAAAAAAAAAAAAAAAAAA8A+sQcADrEHAAaxBwAGsQcCArEFAAKxBRmSsQUfgrEEn4qxBB+KsQRPDrEEBg6xBgAOsQYADrEHAA6xB8A+sQQ==";
+
+var data = atob(dataURL.substring( "data:image/vnd.microsoft.icon;base64,".length ) );
+var asArray = new Uint8Array(data.length);
+for( var i = 0, len = data.length; i < len; ++i ) {
+ asArray[i] = data.charCodeAt(i);
+}
+var blob = new Blob( [ asArray.buffer ], {type: 'image/vnd.microsoft.icon'});
+var url = URL.createObjectURL(blob);
+
+//create img
+var img = document.createElement("img");
+img.id = "img-ori";
+img.src = url;
+document.body.appendChild(img);
+
+img = document.createElement("img");
+img.id = "img-res32";
+img.src = url + '#-moz-resolution=32,32';
+document.body.appendChild(img);
+
+img = document.createElement("img");
+img.id = "img-res48";
+img.src = url + '#-moz-resolution=48,48';
+document.body.appendChild(img);
+
+window.URL.revokeObjectURL(url);
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/reftest/test_xmlPrettyPrint_csp-ref.xml b/dom/base/test/reftest/test_xmlPrettyPrint_csp-ref.xml
new file mode 100644
index 0000000000..7b3c180912
--- /dev/null
+++ b/dom/base/test/reftest/test_xmlPrettyPrint_csp-ref.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<xml>
+ This is an XML document
+</xml>
diff --git a/dom/base/test/reftest/test_xmlPrettyPrint_csp.xml b/dom/base/test/reftest/test_xmlPrettyPrint_csp.xml
new file mode 100644
index 0000000000..7b3c180912
--- /dev/null
+++ b/dom/base/test/reftest/test_xmlPrettyPrint_csp.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<xml>
+ This is an XML document
+</xml>
diff --git a/dom/base/test/reftest/test_xmlPrettyPrint_csp.xml^headers^ b/dom/base/test/reftest/test_xmlPrettyPrint_csp.xml^headers^
new file mode 100644
index 0000000000..93d453bd3b
--- /dev/null
+++ b/dom/base/test/reftest/test_xmlPrettyPrint_csp.xml^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'none';
diff --git a/dom/base/test/script-1_bug597345.sjs b/dom/base/test/script-1_bug597345.sjs
new file mode 100644
index 0000000000..00180c997f
--- /dev/null
+++ b/dom/base/test/script-1_bug597345.sjs
@@ -0,0 +1,22 @@
+// timer has to be alive so it can't be eaten by the GC.
+var timer;
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/javascript", false);
+ // The "stray" open comment at the end of the write is important!
+ response.write(
+ "document.write(\"<script charset='utf-8' src='script-2_bug597345.js'></script><!--\")"
+ );
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"].createInstance(
+ Components.interfaces.nsITimer
+ );
+ timer.initWithCallback(
+ function () {
+ response.finish();
+ },
+ 200,
+ Components.interfaces.nsITimer.TYPE_ONE_SHOT
+ );
+}
diff --git a/dom/base/test/script-2_bug597345.js b/dom/base/test/script-2_bug597345.js
new file mode 100644
index 0000000000..b464373b55
--- /dev/null
+++ b/dom/base/test/script-2_bug597345.js
@@ -0,0 +1 @@
+document.write("Räksmörgås");
diff --git a/dom/base/test/script_bug1238440.js b/dom/base/test/script_bug1238440.js
new file mode 100644
index 0000000000..1fc8422940
--- /dev/null
+++ b/dom/base/test/script_bug1238440.js
@@ -0,0 +1,33 @@
+/* eslint-env mozilla/chrome-script */
+
+Cu.importGlobalProperties(["File"]);
+
+var tmpFile;
+
+function writeFile(text, answer) {
+ var stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
+ Ci.nsIFileOutputStream
+ );
+ stream.init(tmpFile, 0x02 | 0x08 | 0x10, 0o600, 0);
+ stream.write(text, text.length);
+ stream.close();
+
+ File.createFromNsIFile(tmpFile).then(function (file) {
+ sendAsyncMessage(answer, { file });
+ });
+}
+
+addMessageListener("file.open", function (e) {
+ tmpFile = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIDirectoryService)
+ .QueryInterface(Ci.nsIProperties)
+ .get("TmpD", Ci.nsIFile);
+ tmpFile.append("foo.txt");
+ tmpFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
+
+ writeFile("hello world", "file.opened");
+});
+
+addMessageListener("file.change", function (e) {
+ writeFile("hello world---------------", "file.changed");
+});
diff --git a/dom/base/test/script_bug602838.sjs b/dom/base/test/script_bug602838.sjs
new file mode 100644
index 0000000000..e3e7e3fde5
--- /dev/null
+++ b/dom/base/test/script_bug602838.sjs
@@ -0,0 +1,43 @@
+function setOurState(data) {
+ x = {
+ data,
+ QueryInterface(iid) {
+ return this;
+ },
+ };
+ x.wrappedJSObject = x;
+ setObjectState("bug602838", x);
+}
+
+function getOurState() {
+ var data;
+ getObjectState("bug602838", function (x) {
+ // x can be null if no one has set any state yet
+ if (x) {
+ data = x.wrappedJSObject.data;
+ }
+ });
+ return data;
+}
+
+function handleRequest(request, response) {
+ if (request.queryString) {
+ let blockedResponse = getOurState();
+ if (typeof blockedResponse == "object") {
+ blockedResponse.finish();
+ setOurState(null);
+ } else {
+ setOurState("unblocked");
+ }
+ return;
+ }
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/javascript", false);
+ response.write(
+ "ok(asyncRan, 'Async script should have run first.'); firstRan = true;"
+ );
+ if (getOurState() != "unblocked") {
+ response.processAsync();
+ setOurState(response);
+ }
+}
diff --git a/dom/base/test/script_postmessages_fileList.js b/dom/base/test/script_postmessages_fileList.js
new file mode 100644
index 0000000000..0287885c8b
--- /dev/null
+++ b/dom/base/test/script_postmessages_fileList.js
@@ -0,0 +1,26 @@
+/* eslint-env mozilla/chrome-script */
+
+Cu.importGlobalProperties(["File"]);
+
+addMessageListener("file.open", function () {
+ var testFile = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIDirectoryService)
+ .QueryInterface(Ci.nsIProperties)
+ .get("ProfD", Ci.nsIFile);
+ testFile.append("prefs.js");
+
+ File.createFromNsIFile(testFile).then(function (file) {
+ sendAsyncMessage("file.opened", { file });
+ });
+});
+
+addMessageListener("dir.open", function () {
+ var testFile = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIDirectoryService)
+ .QueryInterface(Ci.nsIProperties)
+ .get("ProfD", Ci.nsIFile);
+
+ sendAsyncMessage("dir.opened", {
+ dir: testFile.path,
+ });
+});
diff --git a/dom/base/test/send_gzip_content.sjs b/dom/base/test/send_gzip_content.sjs
new file mode 100644
index 0000000000..f78b6f8635
--- /dev/null
+++ b/dom/base/test/send_gzip_content.sjs
@@ -0,0 +1,46 @@
+function gzipCompressString(string, obs) {
+ let scs = Cc["@mozilla.org/streamConverters;1"].getService(
+ Ci.nsIStreamConverterService
+ );
+ let listener = Cc["@mozilla.org/network/stream-loader;1"].createInstance(
+ Ci.nsIStreamLoader
+ );
+ listener.init(obs);
+ let converter = scs.asyncConvertData("uncompressed", "gzip", listener, null);
+ let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ stringStream.data = string;
+ converter.onStartRequest(null, null);
+ converter.onDataAvailable(null, stringStream, 0, string.length);
+ converter.onStopRequest(null, null, null);
+}
+
+function produceData() {
+ var chars =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+";
+ var result = "";
+ for (var i = 0; i < 100000; ++i) {
+ result += chars;
+ }
+ return result;
+}
+
+function handleRequest(request, response) {
+ response.processAsync();
+
+ // Generate data
+ var strings_to_send = produceData();
+ response.setHeader("Content-Type", "text/plain", false);
+ response.setHeader("Content-Encoding", "gzip", false);
+
+ let observer = {
+ onStreamComplete(loader, context, status, length, result) {
+ buffer = String.fromCharCode.apply(this, result);
+ response.setHeader("Content-Length", "" + buffer.length, false);
+ response.write(buffer);
+ response.finish();
+ },
+ };
+ gzipCompressString(strings_to_send, observer);
+}
diff --git a/dom/base/test/slow.sjs b/dom/base/test/slow.sjs
new file mode 100644
index 0000000000..7139eb91f3
--- /dev/null
+++ b/dom/base/test/slow.sjs
@@ -0,0 +1,15 @@
+function handleRequest(request, response) {
+ response.processAsync();
+
+ timer = Components.classes["@mozilla.org/timer;1"].createInstance(
+ Components.interfaces.nsITimer
+ );
+ timer.init(
+ function () {
+ response.write("Here the content. But slowly.");
+ response.finish();
+ },
+ 5000,
+ Components.interfaces.nsITimer.TYPE_ONE_SHOT
+ );
+}
diff --git a/dom/base/test/somedatas.resource b/dom/base/test/somedatas.resource
new file mode 100644
index 0000000000..bc277681d2
--- /dev/null
+++ b/dom/base/test/somedatas.resource
@@ -0,0 +1,16 @@
+
+
+retry: 500
+
+data:123456789
+data: 123456789123456789
+data:123456789123456789123456789123456789
+data: 123456789123456789123456789123456789123456789123456789123456789123456789
+:some utf-8 characteres
+data:çãá"'@`~à Ḿyyyy
+
+:test if the character ":"(which is used for comments) isn't misunderstood
+data: :xxabcdefghij
+data:çãá"'@`~à Ḿyyyy : zz
+
+
diff --git a/dom/base/test/somedatas.resource^headers^ b/dom/base/test/somedatas.resource^headers^
new file mode 100644
index 0000000000..6a63b5341d
--- /dev/null
+++ b/dom/base/test/somedatas.resource^headers^
@@ -0,0 +1,3 @@
+Content-Type: text/event-stream
+Cache-Control: no-cache, must-revalidate
+
diff --git a/dom/base/test/test_EventSource_redirects.html b/dom/base/test/test_EventSource_redirects.html
new file mode 100644
index 0000000000..aaf2ff2742
--- /dev/null
+++ b/dom/base/test/test_EventSource_redirects.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=716841
+-->
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Test for Bug 338583</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 bgColor=white>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=716841">Mozilla Bug 716841</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ function doTest(test_id) {
+ source = new EventSource("eventsource_redirect.resource");
+ ok(source.url == "http://mochi.test:8888/tests/dom/base/test/eventsource_redirect.resource", "Test failed.");
+ ok(source.readyState == 0 || source.readyState == 1, "Test failed.");
+
+ source.onopen = function (event) {
+ ok(true, "opened");
+ };
+
+ source.onmessage = function (event) {
+ ok(true, "event received");
+ source.close();
+ SimpleTest.finish();
+ };
+
+ source.onerror = function (event) {
+ ok(false, "received onError: " + event);
+ source.close();
+ SimpleTest.finish();
+ };
+
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+</script>
+</pre>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_Image_constructor.html b/dom/base/test/test_Image_constructor.html
new file mode 100644
index 0000000000..4c4bb70e54
--- /dev/null
+++ b/dom/base/test/test_Image_constructor.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=862702
+-->
+<head>
+ <meta charset="utf-8">
+ <!-- Make sure our script runs before anything else -->
+ <script>
+ var img = new Image;
+ </script>
+ <title>Test for Bug 862702</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 862702 **/
+ is(Object.getPrototypeOf(img), HTMLImageElement.prototype,
+ "Wrong prototype object");
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=862702">Mozilla Bug 862702</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_NodeIterator_basics_filters.xhtml b/dom/base/test/test_NodeIterator_basics_filters.xhtml
new file mode 100644
index 0000000000..47504eebbe
--- /dev/null
+++ b/dom/base/test/test_NodeIterator_basics_filters.xhtml
@@ -0,0 +1,178 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!-- NodeIterator basics and filters tests.
+ Originally written by Ian Hickson, Mochi-ified by Zack Weinberg.
+ This file based on 001.xml, 002.xml, and 010.xml from
+ http://hixie.ch/tests/adhoc/dom/traversal/node-iterator/
+ with some additional cases.
+ -->
+<head>
+ <title>DOM Traversal: NodeIterator: Basics and Filters</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">
+<!-- comment -->
+<?body processing instruction?>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript"><![CDATA[
+ function compare_arrays(e, f, label) {
+ var length = (e.length > f.length) ? e.length : f.length;
+ for (var i = 0; i < length; i += 1) {
+ if (e[i] > 0)
+ is(f[i], e[i], label + " - index " + i + ": ");
+ else
+ todo_is(f[i], -e[i], label + " - index " + i + ": ");
+ }
+ }
+
+ /** DOM Traversal: NodeIterator: Basics **/
+ // NOTE: If you change the document structure, you have to make sure
+ // the magic numbers in this array (and 'expected_f', below) match.
+ var expected = new Array(9, // document
+ 1, // html
+ 3, 8, // leading comment
+ 3, 1, // head
+ 3, 1, 3, // title
+ 3, 1, // first script tag
+ 3, 1, // stylesheet tag
+ 3, // close head
+ 3, 1, // body
+ 3, 1, // p#display
+ 3, 1, // div#content
+ 3, 8, // comment
+ 3, 7, // processing instruction
+ 3, // close div
+ 3, 1, // pre#test
+ 3, 1, 4, // script and CDATA block
+ -3, -3, -3); // close close close
+ // these aren't there
+ // not sure why
+ var found = new Array();
+
+ var iterator = document.createNodeIterator(document,
+ NodeFilter.SHOW_ALL,
+ null);
+ var node;
+
+ // forwards
+ while (node = iterator.nextNode())
+ found.push(node.nodeType);
+ compare_arrays(expected, found, 'basics forward');
+
+ // backwards
+ found.length = 0;
+ while (node = iterator.previousNode())
+ found.unshift(node.nodeType);
+ compare_arrays(expected, found, 'basics backward');
+
+ /** DOM Traversal: NodeIterator: Filters **/
+ function filter(n) {
+ if (n.nodeType == 3) {
+ return NodeFilter.FILTER_SKIP;
+ } else if (n.nodeName == 'body') {
+ return NodeFilter.FILTER_REJECT; // same as _SKIP
+ }
+ return 1; // FILTER_ACCEPT
+ }
+
+ // Same warning applies to this array as to 'expected'.
+ var expect_f = new Array(9, // document
+ 1, // html
+ 8, // leading comment
+ 1, // head
+ 1, // title
+ 1, // first script tag
+ 1, // stylesheet tag
+ // body skipped
+ 1, // p#display
+ 1, // div#content
+ 8, // comment
+ // processing instruction skipped
+ 1, // pre#test
+ 1, 4); // script and CDATA block
+
+ found.length = 0;
+ iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL,
+ filter);
+
+ // forwards
+ while (node = iterator.nextNode())
+ found.push(node.nodeType);
+ compare_arrays(expect_f, found, 'filtered forward');
+
+ // backwards
+ found.length = 0;
+ while (node = iterator.previousNode())
+ found.unshift(node.nodeType);
+ compare_arrays(expect_f, found, 'filtered backward');
+
+ function checkBadFilter(method, n) {
+ var iter =
+ document.createNodeIterator(document, NodeFilter.SHOW_ALL,
+ function() {
+ if (n < 0)
+ iter.detach();
+ return NodeFilter.FILTER_ACCEPT;
+ });
+ while (--n >= 0)
+ iter.nextNode();
+ try {
+ iter[method]();
+ ok(true, "Able to call " + method + " on a NodeIterator after calling no-op detach()");
+ } catch (x) { ok(false, x) }
+ }
+ checkBadFilter("nextNode", 2);
+ checkBadFilter("previousNode", 3);
+
+ (function() {
+ // Implementing the scenario outlined in
+ // http://bugzilla.mozilla.org/show_bug.cgi?id=552110#c4
+
+ var iter = (function(filt) {
+ var grandparent = document.createElement("div"),
+ parent = document.createElement("span");
+
+ grandparent.appendChild(parent);
+ parent.appendChild(document.createElement("img"));
+ parent.appendChild(document.createElement("p"));
+
+ return document.createNodeIterator(grandparent,
+ NodeFilter.SHOW_ALL,
+ filt);
+ })(function(n) {
+ if (n.nodeName != "img")
+ return NodeFilter.FILTER_ACCEPT;
+
+ iter.detach();
+
+ n.parentNode.remove();
+ // Drop any node references passed into this function.
+ for (var i = 0; i < arguments.length; ++i)
+ arguments[i] = null;
+ ok(!n, "arguments[0] = null should have nulled out n");
+
+ // Try to trigger GC.
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", location.href, false);
+ xhr.send();
+
+ return NodeFilter.FILTER_SKIP;
+ });
+
+ is(iter.nextNode().nodeName, "div",
+ "iter.nextNode() returned the wrong node");
+ is(iter.nextNode().nodeName, "span",
+ "iter.nextNode() returned the wrong node");
+ try {
+ var p = iter.nextNode();
+ ok(false, "iter.nextNode() should have thrown, but instead it returned <" + p.nodeName + ">");
+ } catch (x) { ok(true, x) }
+ })();
+
+]]></script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_NodeIterator_mutations_1.xhtml b/dom/base/test/test_NodeIterator_mutations_1.xhtml
new file mode 100644
index 0000000000..5f6dc2f861
--- /dev/null
+++ b/dom/base/test/test_NodeIterator_mutations_1.xhtml
@@ -0,0 +1,204 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!-- NodeIterator mutation tests.
+ Originally written by Ian Hickson, Mochi-ified by Zack Weinberg.
+ This file based on 00[3-9].xml from
+ http://hixie.ch/tests/adhoc/dom/traversal/node-iterator/
+ -->
+<head>
+ <title>DOM Traversal: NodeIterator: Mutations (1/x)</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">
+<span id="X"></span><span id="Y"><span id="root1"><span id="A"><span id="B"><span id="C"><span id="D"><span id="E"></span></span></span></span></span></span></span>
+<span id="root2"><span id="F"><span id="FF"></span></span><span id="G"></span><span id="H"><span id="HH"></span></span></span>
+<span id="root3"><span id="I"><span id="II"></span></span><span id="J"></span><span id="K"><span id="KK"></span></span></span>
+<span id="root4"><span id="L"></span><span id="M"><span id="MM"></span></span><span id="N"></span></span>
+<span id="root5"><span id="O"></span><span id="P"><span id="PP"></span></span><span id="Q"></span></span>
+<span id="root6"><span id="R"></span><span id="S"><span id="SS"></span></span><span id="T"></span></span>
+<span id="root7"><span id="U"></span><span id="V"><span id="VV"></span></span><span id="W"></span></span>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript"><![CDATA[
+ /** Originally written by Ian Hickson. **/
+
+ function check(f, e, label) {
+ var eid = e.id;
+ var fid = f ? f.id : 'null';
+ is(f, e, label + ': expected ' + eid + ' have ' + fid);
+ }
+
+ var childid = 0;
+ function addChildTo(a) {
+ var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+ x.id = 'X' + childid;
+ childid++;
+ ok(a, 'parent ' + (a?a.id:'undefined') + ' for child ' + x.id);
+ if (a)
+ a.appendChild(x);
+ return x;
+ }
+ function remove(a) {
+ var p = a.parentNode;
+ ok(a && p,
+ 'removing ' + ( a?(a.id?a.id:'(no id)'):'undefined' )
+ + ' with parent ' + ( p?(p.id?p.id:'(no id)'):'undefined' ));
+ if (a && p)
+ p.removeChild(a);
+ }
+
+ /** Removal of nodes that should have no effect **/
+ (function () {
+ var root = $('root1');
+ var A = $('A');
+ var B = $('B');
+ var C = $('C');
+ var D = $('D');
+ var E = $('E');
+
+ var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+ null);
+ check(iterator.nextNode(), root, '1.0');
+
+ // 1. Remove a node unrelated to the reference node
+ remove($('X'));
+ check(iterator.nextNode(), A, '1.1');
+
+ // 2. Remove an ancestor of the root node
+ remove($('Y'));
+ check(iterator.nextNode(), B, '1.2');
+
+ // 3. Remove the root node itself
+ remove(root);
+ check(iterator.nextNode(), C, '1.3');
+
+ // 4. Remove a descendant of the reference node
+ remove(E);
+ check(iterator.nextNode(), D, '1.4');
+ })();
+
+ /** Removal of the reference node **/
+ (function () {
+ var root = $('root2');
+ var F = $('F');
+ var FF = $('FF');
+ var G = $('G');
+ var H = $('H');
+ var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+ null);
+
+ check(iterator.nextNode(), root, '2.0');
+ check(iterator.nextNode(), F, '2.1');
+ check(iterator.nextNode(), FF, '2.2');
+ check(iterator.nextNode(), G, '2.3');
+ remove(G);
+ check(iterator.previousNode(), FF, '2.4');
+ remove(FF);
+ check(iterator.nextNode(), H, '2.5');
+ })();
+
+ /** Removal of the reference node (deep check) **/
+ (function () {
+ var root = $('root3');
+ var I = $('I');
+ var II = $('II');
+ var J = $('J');
+ var K = $('K');
+ var KK = $('KK');
+
+ var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+ null);
+ check(iterator.nextNode(), root, '3.0');
+ check(iterator.nextNode(), I, '3.1');
+ check(iterator.nextNode(), II, '3.2');
+ check(iterator.nextNode(), J, '3.3');
+ remove(J);
+ var X = addChildTo(II);
+ check(iterator.nextNode(), X, '3.4');
+ check(iterator.previousNode(), X, '3.5');
+ remove(X);
+ var Y = addChildTo(II);
+ check(iterator.previousNode(), Y, '3.6');
+ check(iterator.nextNode(), Y, '3.7');
+ check(iterator.nextNode(), K, '3.8');
+ check(iterator.nextNode(), KK, '3.9');
+ })();
+
+ /** Removal of an ancestor of the Reference Node (forwards) **/
+ (function () {
+ var root = $('root4');
+ var L = $('L');
+ var M = $('M');
+ var MM = $('MM');
+ var N = $('N');
+
+ var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+ null);
+ check(iterator.nextNode(), root, '4.1');
+ check(iterator.nextNode(), L, '4.2');
+ check(iterator.nextNode(), M, '4.3');
+ check(iterator.nextNode(), MM, '4.4');
+ remove(M);
+ check(iterator.previousNode(), L, '4.5');
+ })();
+
+ /** Removal of an ancestor of the Reference Node (forwards) (deep check) **/
+ (function () {
+ var root = $('root5');
+ var O = $('O');
+ var P = $('P');
+ var PP = $('PP');
+ var Q = $('Q');
+
+ var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+ null);
+ check(iterator.nextNode(), root, '5.1');
+ check(iterator.nextNode(), O, '5.2');
+ check(iterator.nextNode(), P, '5.3');
+ check(iterator.nextNode(), PP, '5.4');
+ remove(P);
+ var X = addChildTo(O);
+ check(iterator.nextNode(), X, '5.5');
+ })();
+
+ /** Removal of an ancestor of the Reference Node (backwards) **/
+ (function () {
+ var root = $('root6');
+ var R = $('R');
+ var S = $('S');
+ var SS = $('SS');
+ var T = $('T');
+
+ var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+ null);
+ check(iterator.nextNode(), root, '6.1');
+ check(iterator.nextNode(), R, '6.2');
+ check(iterator.nextNode(), S, '6.3');
+ check(iterator.nextNode(), SS, '6.4');
+ check(iterator.previousNode(), SS, '6.5');
+ remove(S);
+ check(iterator.nextNode(), T, '6.6');
+ })();
+
+ /** Removal of an ancestor of the Reference Node (backwards) (deep check) **/
+ (function () {
+ var root = $('root7');
+ var U = $('U');
+ var V = $('V');
+ var VV = $('VV');
+ var W = $('W');
+
+ var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ALL,
+ null);
+ check(iterator.nextNode(), root, '7.1');
+ check(iterator.nextNode(), U, '7.2');
+ check(iterator.nextNode(), V, '7.3');
+ check(iterator.nextNode(), VV, '7.4');
+ check(iterator.previousNode(), VV, '7.5');
+ remove(V);
+ var X = addChildTo(U);
+ check(iterator.previousNode(), X, '7.6');
+ })();
+]]></script></pre></body></html>
diff --git a/dom/base/test/test_NodeIterator_mutations_2.html b/dom/base/test/test_NodeIterator_mutations_2.html
new file mode 100644
index 0000000000..47d7b8b5e4
--- /dev/null
+++ b/dom/base/test/test_NodeIterator_mutations_2.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML>
+<html>
+<!-- NodeIterator mutation tests, 2.
+ Originally part of WebKit, Mochi-ified by Zack Weinberg.
+ This file based on node-iterator-00[...].html from
+ http://svn.webkit.org/repository/webkit/trunk/LayoutTests/traversal/
+ -->
+<head>
+ <title>DOM Traversal: NodeIterator: Mutations (2/x)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+</head>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ function resetContent() {
+ var content = $('content');
+ content.innerHTML = ('<span id="A"><\/span><span id="B"><\/span>'
+ + '<span id="C"><\/span><span id="D"><\/span>'
+ + '<span id="E"><\/span><span id="F"><\/span>'
+ + '<span id="G"><\/span><span id="H"><\/span>'
+ + '<span id="I"><\/span>');
+ return content;
+ }
+
+ function makeSpan(id) {
+ var e = document.createElement('span');
+ e.id = id;
+ return e;
+ }
+
+ function testNodeFilter(n) {
+ if (n.tagName == 'SPAN')
+ return NodeFilter.FILTER_ACCEPT;
+ return NodeFilter.FILTER_SKIP;
+ }
+
+ function checkseq(it, root, expect) {
+ var checkIt = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+ var printedPointer = (it.referenceNode == undefined);
+ var string = '';
+ var node;
+ while ((node = checkIt.nextNode()) != null) {
+ if (!printedPointer && it.referenceNode == node) {
+ printedPointer = true;
+ var s = '[' + node.id + '] ';
+ if (it.pointerBeforeReferenceNode)
+ string += "* " + s;
+ else
+ string += s + "* ";
+ } else {
+ string += node.id + " ";
+ }
+ }
+ is(string.slice(0, -1), expect, "sequence check");
+ }
+
+ // first a basic sanity check [node-iterator-001]
+ (function(){
+ var root = resetContent();
+ var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+
+ checkseq(it, root, 'A B C D E F G H I');
+ it.nextNode();
+ checkseq(it, root, '[A] * B C D E F G H I');
+ it.previousNode();
+ checkseq(it, root, '* [A] B C D E F G H I');
+ it.previousNode();
+ checkseq(it, root, '* [A] B C D E F G H I');
+ })();
+
+ // Mutations that should not move the iterator [node-iterator-002]
+ (function(){
+ var root = resetContent();
+ var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+
+ for (var i = 0; i < 4; i++)
+ it.nextNode();
+ checkseq(it, root, 'A B C [D] * E F G H I');
+
+ root.removeChild($('E'));
+ checkseq(it, root, 'A B C [D] * F G H I');
+
+ var X = makeSpan('X');
+ root.insertBefore(X, $('F'));
+ checkseq(it, root, 'A B C [D] * X F G H I');
+
+ var I = $('I');
+ root.removeChild(I);
+ root.insertBefore(I, X);
+ checkseq(it, root, 'A B C [D] * I X F G H');
+ })();
+
+ // 002 complete
+
+ /* Template
+ (function(){
+ var root = resetContent();
+ var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+
+ })();
+ */
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_NodeIterator_mutations_3.html b/dom/base/test/test_NodeIterator_mutations_3.html
new file mode 100644
index 0000000000..3eb23ee3ce
--- /dev/null
+++ b/dom/base/test/test_NodeIterator_mutations_3.html
@@ -0,0 +1,160 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>DOM Traversal: NodeIterator: Mutations (3/x)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+</head>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <span id=root><span id=B></span><span id=C></span><span id=D></span><span id=E><span id=E1><span id=E11></span></span></span></span>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ function removeNode(n) {
+ n.remove();
+ }
+ var initInner = $('content').innerHTML;
+ var content = $('content');
+
+
+ function resetContent() {
+ content.innerHTML = initInner;
+ var checkIt = document.createNodeIterator(content, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+ var node;
+ while ((node = checkIt.nextNode()) != null) {
+ if (node.id) {
+ window[node.id] = node;
+ }
+ }
+ }
+
+ function makeSpan(id) {
+ var e = document.createElement('span');
+ e.id = id;
+ return e;
+ }
+
+ function testNodeFilter(n) {
+ if (n.tagName == 'SPAN')
+ return NodeFilter.FILTER_ACCEPT;
+ return NodeFilter.FILTER_SKIP;
+ }
+
+ function checkseq(it, root, expect) {
+ var checkIt = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+ var printedPointer = (it.referenceNode == undefined);
+ var string = '';
+ var node;
+ while ((node = checkIt.nextNode()) != null) {
+ if (!printedPointer && it.referenceNode == node) {
+ printedPointer = true;
+ var s = '[' + node.id + '] ';
+ if (it.pointerBeforeReferenceNode)
+ string += "* " + s;
+ else
+ string += s + "* ";
+ } else {
+ string += node.id + " ";
+ }
+ }
+ is(string.slice(0, -1), expect, "sequence check");
+ }
+
+ resetContent();
+ var it = document.createNodeIterator(E, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+ checkseq(it, root, "root B C D * [E] E1 E11");
+
+ removeNode(C);
+ checkseq(it, root, "root B D * [E] E1 E11");
+
+ it.nextNode();
+ removeNode(D);
+ checkseq(it, root, "root B [E] * E1 E11");
+
+ it.nextNode();
+ removeNode(B);
+ checkseq(it, root, "root E [E1] * E11");
+
+ it.nextNode();
+ checkseq(it, root, "root E E1 [E11] *");
+
+ it.nextNode();
+ checkseq(it, root, "root E E1 [E11] *");
+
+ it.previousNode();
+ it.previousNode();
+ it.previousNode();
+ it.previousNode();
+ it.previousNode();
+ checkseq(it, root, "root * [E] E1 E11");
+
+ resetContent();
+ it = document.createNodeIterator(E, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+ checkseq(it, root, "root B C D * [E] E1 E11");
+
+ it.nextNode();
+ it.nextNode();
+ checkseq(it, root, "root B C D E [E1] * E11");
+
+ it.previousNode();
+ it.previousNode();
+ checkseq(it, root, "root B C D * [E] E1 E11");
+
+ removeNode(D);
+ removeNode(B);
+ checkseq(it, root, "root C * [E] E1 E11");
+
+ n = makeSpan('n');
+ root.insertBefore(n, E);
+ checkseq(it, root, "root C n * [E] E1 E11");
+
+ n2 = makeSpan('n2');
+ root.insertBefore(n2, C);
+ checkseq(it, root, "root n2 C n * [E] E1 E11");
+
+ resetContent();
+ it = document.createNodeIterator(E, NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+ checkseq(it, root, "root B C D * [E] E1 E11");
+
+ removeNode(root);
+ checkseq(it, root, "root B C D * [E] E1 E11");
+
+ removeNode(B);
+ checkseq(it, root, "root C D * [E] E1 E11");
+
+ removeNode(D);
+ checkseq(it, root, "root C * [E] E1 E11");
+
+ it.nextNode();
+ it.nextNode();
+ it.nextNode();
+ checkseq(it, root, "root C E E1 [E11] *");
+
+ removeNode(E1);
+ checkseq(it, root, "root C [E] *");
+
+ n = makeSpan('n');
+ root.insertBefore(n, E);
+ checkseq(it, root, "root C n [E] *");
+
+ n2 = makeSpan('n2');
+ E.appendChild(n2);
+ checkseq(it, root, "root C n [E] * n2");
+
+ it.nextNode();
+ checkseq(it, root, "root C n E [n2] *");
+
+ removeNode(E);
+ checkseq(it, root, "root C n");
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_anchor_area_referrer.html b/dom/base/test/test_anchor_area_referrer.html
new file mode 100644
index 0000000000..7e6992b404
--- /dev/null
+++ b/dom/base/test/test_anchor_area_referrer.html
@@ -0,0 +1,127 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test anchor and area policy attribute for Bug 1174913</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that anchor and area referrer attributes are honoured correctly
+ * anchor tag with referrer attribute (generate-anchor-policy-test)
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
+ -->
+
+ <script type="application/javascript">
+
+ SimpleTest.requestLongerTimeout(2);
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL", "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-anchor-policy-test", "generate-area-policy-test"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "unsafe-url (anchor) with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ DESC: "origin (anchor) with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'no-referrer-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "no-referrer (anchor) with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "same-origin with origin in meta",
+ RESULT: 'full'},
+ {NAME: 'no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ DESC: "no-referrer in meta",
+ RESULT: 'none'},
+
+ // Test if element attr would override meta referr policy.
+
+ // 1. Downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta downgrade in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin-when-cross-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+
+ // 2. No downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta downgrade in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin-when-cross-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'strict-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ DESC: "strict-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ DESC: "same-origin with origin in meta",
+ RESULT: 'none'},
+
+ // End of element attr overriding test..
+
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'origin-with-no-meta',
+ META_POLICY: '',
+ DESC: "origin (anchor) with no meta",
+ RESULT: 'origin'}]}
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_anchor_area_referrer_changing.html b/dom/base/test/test_anchor_area_referrer_changing.html
new file mode 100644
index 0000000000..e8d6c249fb
--- /dev/null
+++ b/dom/base/test/test_anchor_area_referrer_changing.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test anchor and area policy attribute for Bug 1174913</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that anchor and area referrer attributes are honoured correctly
+ This test is split due to errors on b2g
+ * testing setAttribute and .referrer (generate-anchor-changing-test)
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL"];
+
+ const testCases = [
+ {ACTION: ["generate-anchor-changing-policy-test-set-attribute", "generate-area-changing-policy-test-set-attribute"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NEW_ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'no-referrer-unsafe-url-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "no-referrer (anchor, orginally unsafe-url) with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-origin-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ DESC: "unsafe-url (anchor, orginally origin) with no-referrer in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-origin-with-no-referrer-in-meta-rel',
+ META_POLICY: 'no-referrer',
+ DESC: "unsafe-url (anchor, orginally origin) with no-referrer in meta and rel=noreferrer",
+ RESULT: 'none',
+ REL: 'noreferrer'}]},
+ {ACTION: ["generate-anchor-changing-policy-test-property", "generate-area-changing-policy-test-property"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-no-referrer-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "unsafe-url (anchor, orginally no-referrer) with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-no-referrer-with-origin-in-meta-rel',
+ META_POLICY: 'origin',
+ DESC: "unsafe-url (anchor, orginally no-referrer) with origin in meta and rel=noreferrer",
+ RESULT: 'none',
+ REL: 'noreferrer'}]}
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_anchor_area_referrer_invalid.html b/dom/base/test/test_anchor_area_referrer_invalid.html
new file mode 100644
index 0000000000..f5687b7180
--- /dev/null
+++ b/dom/base/test/test_anchor_area_referrer_invalid.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test anchor and area policy attribute for Bug 1174913</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that anchor and area referrer attributes are honoured correctly
+ * anchor tag with invalid referrer attributes
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL", , "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-anchor-policy-test", "generate-area-policy-test"],
+ TESTS: [
+ // setting invalid refer values -> we expect either full referrer (default)
+ // or whatever is specified in the meta referrer policy
+
+ // Note that for those test cases which require cross-origin test, we use different
+ // scheme to result in cross-origin request.
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-no-meta',
+ META_POLICY: '',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ DESC: "origin-when-cross-origin (anchor) with no meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'default',
+ NAME: 'default-with-no-meta',
+ META_POLICY: '',
+ DESC: "default (anchor) with no meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'something',
+ NAME: 'something-with-no-meta',
+ META_POLICY: '',
+ DESC: "something (anchor) with no meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ DESC: "origin-when-cross-origin (anchor) with no-referrer in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ DESC: "origin-when-cross-origin (anchor) with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ DESC: "origin-when-cross-origin (anchor) with origin in meta",
+ RESULT: 'origin'}]}
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_anchor_area_referrer_rel.html b/dom/base/test/test_anchor_area_referrer_rel.html
new file mode 100644
index 0000000000..71cd4f6390
--- /dev/null
+++ b/dom/base/test/test_anchor_area_referrer_rel.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test anchor and area policy attribute for Bug 1174913</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that anchor and area referrer attributes are honoured correctly
+ * anchor tag with referrer attribute with rel=noreferrer
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1174913
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL"];
+
+ const testCases = [
+ {ACTION: ["generate-anchor-policy-test", "generate-area-policy-test"],
+ TESTS: [
+ // setting rel=noreferrer -> we expect no referrer
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-with-origin-in-meta-rel',
+ META_POLICY: 'origin',
+ DESC: "unsafe-url (anchor) with origin in meta and rel=noreferrer",
+ RESULT: 'none',
+ REL: 'noreferrer'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'origin-with-unsafe-url-in-meta-rel',
+ META_POLICY: 'unsafe-url',
+ DESC: "origin (anchor) with unsafe-url in meta and rel=noreferrer",
+ RESULT: 'none',
+ REL: 'noreferrer'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'origin-with-no-meta-rel',
+ META_POLICY: '',
+ DESC: "origin (anchor) with no meta and rel=noreferrer",
+ RESULT: 'none',
+ REL: 'noreferrer'}]}
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_anchor_target_blank_referrer.html b/dom/base/test/test_anchor_target_blank_referrer.html
new file mode 100644
index 0000000000..fbd1ff9207
--- /dev/null
+++ b/dom/base/test/test_anchor_target_blank_referrer.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test anchor target=_blank rel=noopener referrer header for Bug 1502678</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that anchor referrer header are honoured correctly
+ * anchor tag with rel=noopener target=_blank
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1502678
+ -->
+
+ <script type="application/javascript">
+ // We are going to open new tabs with target=_blank and rel=noopener
+ // Listen a new tab is opened then close the new tab, otherwise we will lose
+ // focus for the next tests
+ const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
+ const gBrowser = Services.wm.getMostRecentWindow("navigator:browser").gBrowser;
+ window.addEventListener("message", function(event) {
+ if (event.data == "childLoadReady") {
+ BrowserTestUtils.waitForNewTab(gBrowser, null,
+ true).then(function(aNewTab) {
+ BrowserTestUtils.removeTab(aNewTab);
+ advance();
+ });
+ }
+ });
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["RP_HEADER", "META_POLICY", "REL", "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-anchor-target-blank-policy-test"],
+ TESTS: [
+ // Referrer policy is set in meta
+ {NAME: 'origin-in-meta-rel-noopener',
+ META_POLICY: 'origin',
+ DESC: "origin in meta and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'origin'},
+ {NAME: 'unsafe-url-in-meta-rel-noopener',
+ META_POLICY: 'unsafe-url',
+ DESC: "unsafe-url in meta and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'full'},
+ {NAME: 'no-referrer-in-meta-rel-noopener',
+ META_POLICY: 'no-referrer',
+ DESC: "no-referrer in meta and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'strict-origin-in-meta-rel-noopener',
+ META_POLICY: 'strict-origin',
+ DESC: "strict-origin in meta and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'strict-origin-when-cross-origin-in-meta-rel-noopener',
+ META_POLICY: 'strict-origin-when-cross-origin',
+ DESC: "strict-origin-when-cross-origin in meta and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'same-origin-in-meta-rel-noopener',
+ META_POLICY: 'same-origin',
+ DESC: "same-origin in meta and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'no-meta-rel-noopener',
+ META_POLICY: '',
+ DESC: "no meta and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+
+ // Referrer policy is set in Referrer-Policy Header
+ {NAME: 'origin-in-referrer-policy-header-rel-noopener',
+ RP_HEADER: 'origin',
+ DESC: "origin in Referrer-Policy Header and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'origin'},
+ {NAME: 'unsafe-url-in-referrer-policy-header-rel-noopener',
+ RP_HEADER: 'unsafe-url',
+ DESC: "unsafe-url in Referrer-Policy Header and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'full'},
+ {NAME: 'no-referrer-in-referrer-policy-header-rel-noopener',
+ RP_HEADER: 'no-referrer',
+ DESC: "no-referrer in Referrer-Policy Header and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'strict-origin-in-referrer-policy-header-rel-noopener',
+ RP_HEADER: 'strict-origin',
+ DESC: "strict-origin in Referrer-Policy Header and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'strict-origin-when-cross-origin-in-referrer-policy-header-rel-noopener',
+ RP_HEADER: 'strict-origin-when-cross-origin',
+ DESC: "strict-origin-when-cross-origin in Referrer-Policy Header and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'same-origin-in-referrer-policy-header-rel-noopener',
+ RP_HEADER: 'same-origin',
+ DESC: "same-origin in Referrer-Policy Header and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {NAME: 'no-referrer-policy-header-rel-noopener',
+ RP_HEADER: '',
+ DESC: "no Referrer-Policy Header and rel=noopener",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'}
+
+ ]}
+ ];
+ </script>
+ <script type="application/javascript" src="referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_anonymousContent_api.html b/dom/base/test/test_anonymousContent_api.html
new file mode 100644
index 0000000000..2bc8d08e62
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_api.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1020244
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1020244 - Test the chrome-only AnonymousContent API</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=1020244">Mozilla Bug 1020244</a>
+ <script type="application/javascript">
+
+ // Testing the presence of the chrome-only API
+ ok(!document.insertAnonymousContent,
+ "Content document shouldn't have access to insertAnonymousContent");
+ ok(!document.removeAnonymousContent,
+ "Content document shouldn't have access to removeAnonymousContent");
+
+ let chromeDocument = SpecialPowers.wrap(document);
+ ok(chromeDocument.insertAnonymousContent,
+ "Chrome document should have access to insertAnonymousContent");
+ ok(chromeDocument.removeAnonymousContent,
+ "Chrome document should have access to removeAnonymousContent");
+
+ // Testing invalid inputs
+ let invalidNodes = [null, undefined, false, 1, "string"];
+ for (let node of invalidNodes) {
+ let didThrow = false;
+ try {
+ chromeDocument.insertAnonymousContent(node);
+ } catch (e) {
+ didThrow = true;
+ }
+ ok(didThrow, "Passing an invalid node to insertAnonymousContent should throw");
+ }
+
+ // Testing the API of the returned object
+ let div = document.createElement("div");
+ div.textContent = "this is a test element";
+ let anonymousContent = chromeDocument.insertAnonymousContent(div);
+ ok(anonymousContent, "AnonymousContent object returned");
+
+ let members = ["getTextContentForElement", "setTextContentForElement",
+ "getAttributeForElement", "setAttributeForElement",
+ "removeAttributeForElement", "getCanvasContext",
+ "setAnimationForElement", "setStyle"];
+ for (let member of members) {
+ ok(member in anonymousContent, "AnonymousContent object defines " + member);
+ }
+ chromeDocument.removeAnonymousContent(anonymousContent);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_anonymousContent_append_after_reflow.html b/dom/base/test/test_anonymousContent_append_after_reflow.html
new file mode 100644
index 0000000000..1e1e62d3d5
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_append_after_reflow.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1020244 -->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1020244 - Make sure anonymous content still works after a reflow (after the canvasframe has been reconstructed)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div>
+ <div id="test-element" style="color:red;">text content</div>
+</div>
+<script type="application/javascript">
+ info("Inserting anonymous content into the document frame");
+ let chromeDocument = SpecialPowers.wrap(document);
+ let testElement = document.querySelector("div");
+ let anonymousContent = chromeDocument.insertAnonymousContent(testElement);
+
+ info("Modifying the style of an element in the anonymous content");
+ let style = anonymousContent.setAttributeForElement("test-element",
+ "style", "color:green;");
+
+ info("Toggling the display style on the document element to force reframing");
+ // Note that we force sync reflows to make sure the canvasframe is recreated
+ // synchronously.
+ document.documentElement.style.display = "none";
+ let forceFlush = document.documentElement.offsetHeight;
+ document.documentElement.style.display = "block";
+ forceFlush = document.documentElement.offsetHeight;
+
+ info("Checking that the anonymous content can be retrieved still");
+ style = anonymousContent.getAttributeForElement("test-element", "style");
+ is(style, "color:green;", "The anonymous content still exists after reflow");
+
+ info("Removing the anonymous content");
+ chromeDocument.removeAnonymousContent(anonymousContent);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_anonymousContent_canvas.html b/dom/base/test/test_anonymousContent_canvas.html
new file mode 100644
index 0000000000..cca364a52d
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_canvas.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1212477
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1212477 - Needs a way to access to &lt;canvas&gt;'s context (2d, webgl) from Anonymous Content API</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=1212477">Mozilla Bug 1212477</a>
+ <div>
+ <div id="id" class="test">text content</div>
+ <canvas id="canvas2d"></canvas>
+ <canvas id="canvas-webgl"></canvas>
+ <canvas id="canvas-foo"></canvas>
+ </div>
+ <script type="application/javascript">
+ let chromeDocument = SpecialPowers.wrap(document);
+ let testElement = document.querySelector("div");
+
+ let anonymousContent = chromeDocument.insertAnonymousContent(testElement);
+
+ is(anonymousContent.getCanvasContext("id", "2d"), null,
+ "Context is null for non-canvas elements");
+
+ let context2d = anonymousContent.getCanvasContext("canvas2d", "2d");
+
+ is(context2d.toString(), "[object CanvasRenderingContext2D]",
+ "2D Context is returned properly");
+
+ is(context2d.canvas, null,
+ "context's canvas property is null in anonymous content");
+
+ is (anonymousContent.getCanvasContext("canvas-foo", "foo"), null,
+ "Context is null for unknown context type");
+
+ SimpleTest.doesThrow(
+ () => anonymousContent.getCanvasContext("foo", "2d"),
+ "NS_ERROR_NOT_AVAILABLE",
+ "Get a context using unexisting id should throw"
+ );
+
+ const normalWebGL = document.createElement('canvas').getContext('webgl');
+ if (normalWebGL) {
+ let webgl = anonymousContent.getCanvasContext("canvas-webgl", "webgl");
+
+ is(webgl.toString(), "[object WebGLRenderingContext]",
+ "WebGL Context is returned properly");
+
+ is(webgl.canvas, null,
+ "WebGL context's canvas property is null in anonymous content");
+ }
+ chromeDocument.removeAnonymousContent(anonymousContent);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_anonymousContent_insert.html b/dom/base/test/test_anonymousContent_insert.html
new file mode 100644
index 0000000000..81e03cb45b
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_insert.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1020244
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1020244 - Insert content using the AnonymousContent API, several times, and don't remove it</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=1020244">Mozilla Bug 1020244</a>
+<div>
+ <div id="id" class="test">text content</div>
+</div>
+ <script type="application/javascript">
+ const INSERTED_NB = 5;
+
+ // Insert the same content several times
+ let chromeDocument = SpecialPowers.wrap(document);
+ let testElement = document.querySelector("div");
+
+ let anonymousContents = [];
+ for (let i = 0; i < INSERTED_NB; i ++) {
+ let content = chromeDocument.insertAnonymousContent(testElement);
+ // Adding an expando pointing to the document to make sure this doesn't
+ // cause leaks.
+ content.dummyExpando = testElement.ownerDocument;
+ anonymousContents.push(content);
+ }
+
+ // Make sure that modifying one of the inserted elements does not modify the
+ // other ones.
+ anonymousContents[0].setAttributeForElement("id", "class", "updated");
+ for (let i = 1; i < INSERTED_NB; i ++) {
+ is(anonymousContents[i].getAttributeForElement("id", "class"),
+ "test",
+ "Element " + i + " didn't change when element 0 was changed");
+ }
+
+ // Do not remove inserted elements on purpose to test for potential leaks too.
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_anonymousContent_manipulate_content.html b/dom/base/test/test_anonymousContent_manipulate_content.html
new file mode 100644
index 0000000000..eb4bcb6be3
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_manipulate_content.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1020244
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1020244 - Manipulate content created with the AnonymousContent API</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=1020244">Mozilla Bug 1020244</a>
+<div>
+ <div id="test-element" class="test-class" test="test">text content</div>
+</div>
+ <script type="application/javascript">
+
+ // Insert content
+ let chromeDocument = SpecialPowers.wrap(document);
+ let testElement = document.querySelector("div");
+ let anonymousContent = chromeDocument.insertAnonymousContent(testElement);
+
+ // Test getting/setting text content.
+ is(anonymousContent.getTextContentForElement("test-element"),
+ "text content", "Textcontent for the test element is correct");
+
+ anonymousContent.setTextContentForElement("test-element",
+ "updated text content");
+ is(anonymousContent.getTextContentForElement("test-element"),
+ "updated text content",
+ "Textcontent for the test element is correct after update");
+
+ // Test that modifying the original DOM element doesn't change the inserted
+ // element.
+ testElement.removeAttribute("test");
+ is(anonymousContent.getAttributeForElement("test-element", "test"),
+ "test",
+ "Removing attributes on the original DOM node does not change the inserted node");
+
+ testElement.setAttribute("test", "test-updated");
+ is(anonymousContent.getAttributeForElement("test-element", "test"),
+ "test",
+ "Setting attributes on the original DOM node does not change the inserted node");
+
+ // Test getting/setting/removing attributes on the inserted element and test
+ // that this doesn't change the original DOM element.
+ is(anonymousContent.getAttributeForElement("test-element", "class"),
+ "test-class", "Class attribute for the test element is correct");
+
+ anonymousContent.setAttributeForElement("test-element", "class",
+ "updated-test-class");
+ is(anonymousContent.getAttributeForElement("test-element", "class"),
+ "updated-test-class",
+ "Class attribute for the test element is correct after update");
+ ok(testElement.getAttribute("class") !== "updated-test-class",
+ "Class attribute change on the inserted node does not change the original DOM node");
+
+ anonymousContent.removeAttributeForElement("test-element", "class");
+ is(anonymousContent.getAttributeForElement("test-element", "class"), null,
+ "Class attribute for the test element was removed");
+
+ let anim = anonymousContent.setAnimationForElement("test-element", [
+ { transform: 'translateY(0px)' },
+ { transform: 'translateY(-300px)' }
+ ], 2000);
+ is(anim.playState, "running", "Animation should be running");
+ anim.cancel();
+ is(anim.playState, "idle", "Animation should have stopped immediately");
+
+ chromeDocument.removeAnonymousContent(anonymousContent);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_anonymousContent_set_style.html b/dom/base/test/test_anonymousContent_set_style.html
new file mode 100644
index 0000000000..75587b3e0f
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_set_style.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1571650
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1571650 - Test AnonymousContent.setStyle() API</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=1571650">Mozilla Bug 1571650</a>
+ <script type="application/javascript">
+ const chromeDocument = SpecialPowers.wrap(document);
+
+ info("Set z-index to anonymous content");
+ const div = document.createElement("div");
+ div.setAttribute("class", "set-style-test");
+ const anonymousContent = chromeDocument.insertAnonymousContent(div);
+ anonymousContent.setStyle("z-index", 3);
+
+ info("Test the element which became to anonymous");
+ const mozCustomContentContainerEl =
+ [...SpecialPowers.InspectorUtils.getChildrenForNode(document.documentElement, true, false)]
+ .find(n => n.classList && n.classList.contains("moz-custom-content-container"));
+
+ const targetEl = mozCustomContentContainerEl.querySelector(".set-style-test");
+ ok(targetEl, "Element which became to anonymous is found");
+ is(targetEl.style.zIndex, "3", "z-index is correct");
+
+ chromeDocument.removeAnonymousContent(anonymousContent);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_anonymousContent_style_csp.html b/dom/base/test/test_anonymousContent_style_csp.html
new file mode 100644
index 0000000000..0eca83404c
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_style_csp.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1020244 -->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1185351 - Make sure that we don't enforce CSP on styles for AnonymousContent</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div>
+ <div id="test-element" style="color:red;">text content</div>
+</div>
+<script type="application/javascript">
+ let chromeDocument = SpecialPowers.wrap(document);
+ let testElement = document.querySelector("div");
+ let anonymousContent = chromeDocument.insertAnonymousContent(testElement);
+
+ let style = anonymousContent.setAttributeForElement("test-element",
+ "style", "color:green;");
+
+ style = anonymousContent.getAttributeForElement("test-element", "style");
+ is(style, "color:green;", "The anonymous content exists with CSP");
+
+ chromeDocument.removeAnonymousContent(anonymousContent);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_anonymousContent_style_csp.html^headers^ b/dom/base/test/test_anonymousContent_style_csp.html^headers^
new file mode 100644
index 0000000000..b7b3c8a4f9
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_style_csp.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
diff --git a/dom/base/test/test_anonymousContent_xul_window.xhtml b/dom/base/test/test_anonymousContent_xul_window.xhtml
new file mode 100644
index 0000000000..b81f827075
--- /dev/null
+++ b/dom/base/test/test_anonymousContent_xul_window.xhtml
@@ -0,0 +1,23 @@
+<?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=1020244
+Check that XUL windows don't make insertAnonymousContent crash.
+-->
+<window title="Anonymous content in a XUL window"
+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"></body>
+ <box>This is a test box</box>
+
+ <script type="application/javascript">
+ // Insert content
+ let testElement = document.querySelector("box");
+ document.insertAnonymousContent(testElement);
+ ok(true,
+ "Inserting anonymous content in a XUL document did not crash")
+ </script>
+</window>
diff --git a/dom/base/test/test_appname_override.html b/dom/base/test/test_appname_override.html
new file mode 100644
index 0000000000..bf1162a900
--- /dev/null
+++ b/dom/base/test/test_appname_override.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=939445
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 939445 - general.appname.override</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=939445">Mozilla Bug 939445</a>
+ <script type="application/javascript">
+
+ function runTest() {
+ is(navigator.appName, "hello", "general.appname.override not working");
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({"set": [["general.appname.override", "hello"]]}, runTest);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_async_setTimeout_stack.html b/dom/base/test/test_async_setTimeout_stack.html
new file mode 100644
index 0000000000..773a923be3
--- /dev/null
+++ b/dom/base/test/test_async_setTimeout_stack.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1142577
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1142577 - Async stacks for setTimeout</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=1142577">Mozilla Bug 1142577</a>
+ <pre id="stack"></pre>
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("Testing async stacks across setTimeout");
+
+ function getFunctionName(frame) {
+ return frame.slice(0, frame.indexOf("@"));
+ }
+
+ function a() { b() }
+ function b() { c() }
+ function c() { setTimeout(d, 1) }
+ function d() { e() }
+ function e() { f() }
+ function f() { setTimeout(g, 1) }
+ function g() { h() }
+ function h() { i() }
+ function i() {
+ var stackString = Error().stack;
+ document.getElementById("stack").textContent = stackString;
+
+ var frames = stackString
+ .split("\n")
+ .map(getFunctionName)
+ .filter(function (name) { return !!name; });
+
+ is(frames[0], "i");
+ is(frames[1], "h");
+ is(frames[2], "g");
+ is(frames[3], "setTimeout handler*SimpleTest_setTimeoutShim");
+ is(frames[4], "f");
+ is(frames[5], "e");
+ is(frames[6], "d");
+ is(frames[7], "setTimeout handler*SimpleTest_setTimeoutShim");
+ is(frames[8], "c");
+ is(frames[9], "b");
+ is(frames[10], "a");
+
+ SimpleTest.finish();
+ }
+
+ SpecialPowers.pushPrefEnv(
+ {"set": [['javascript.options.asyncstack_capture_debuggee_only', false]]},
+ a);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_async_setTimeout_stack_across_globals.html b/dom/base/test/test_async_setTimeout_stack_across_globals.html
new file mode 100644
index 0000000000..358aa21abe
--- /dev/null
+++ b/dom/base/test/test_async_setTimeout_stack_across_globals.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1142577
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1142577 - Async stacks for setTimeout</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=1142577">Mozilla Bug 1142577</a>
+ <pre id="stack"></pre>
+ <iframe id="iframe"></iframe>
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ var otherGlobal = document.getElementById("iframe").contentWindow;
+
+ function getFunctionName(frame) {
+ return frame.slice(0, frame.indexOf("@"));
+ }
+
+ function a() { b() }
+ function b() { c() }
+ function c() { otherGlobal.setTimeout(d, 1) }
+ function d() { e() }
+ function e() { f() }
+ function f() { otherGlobal.setTimeout(g, 1) }
+ function g() { h() }
+ function h() { i() }
+ function i() {
+ var stackString = Error().stack;
+ document.getElementById("stack").textContent = stackString;
+
+ var frames = stackString
+ .split("\n")
+ .map(getFunctionName)
+ .filter(function (name) { return !!name; });
+
+ is(frames[0], "i");
+ is(frames[1], "h");
+ is(frames[2], "g");
+ is(frames[3], "setTimeout handler*f");
+ is(frames[4], "e");
+ is(frames[5], "d");
+ is(frames[6], "setTimeout handler*c");
+ is(frames[7], "b");
+ is(frames[8], "a");
+
+ SimpleTest.finish();
+ }
+
+ SpecialPowers.pushPrefEnv(
+ {"set": [['javascript.options.asyncstack_capture_debuggee_only', false]]},
+ a);
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_base.xhtml b/dom/base/test/test_base.xhtml
new file mode 100644
index 0000000000..b61bc72f68
--- /dev/null
+++ b/dom/base/test/test_base.xhtml
@@ -0,0 +1,39 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Test for base URIs</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <base href="/tests/dom/base/" />
+</head>
+<body>
+<div id="1" xml:base="supercalifragilisticexpialidocious"><p><p xml:base="hello/"><p xml:base="world"><span xml:base="#iamtheverymodelofamodernmajorgeneral">text</span></p></p></p></div>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ is(document.baseURI, "http://mochi.test:8888/tests/dom/base/",
+ "document base");
+ is(document.body.baseURI, "http://mochi.test:8888/tests/dom/base/",
+ "body base");
+
+ var expected =
+ ["http://mochi.test:8888/tests/dom/base/",
+ "http://mochi.test:8888/tests/dom/base/",
+ "http://mochi.test:8888/tests/dom/base/",
+ "http://mochi.test:8888/tests/dom/base/",
+ "http://mochi.test:8888/tests/dom/base/",
+ "http://mochi.test:8888/tests/dom/base/",
+ ];
+ var node = document.getElementById("1");
+ while(node) {
+ is(node.baseURI, expected.shift(), "node base");
+ node = node.firstChild;
+ }
+ is(expected.length, 0, "found all expected nodes");
+
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_blockParsing.html b/dom/base/test/test_blockParsing.html
new file mode 100644
index 0000000000..05f104ce62
--- /dev/null
+++ b/dom/base/test/test_blockParsing.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for document.blockParsing</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+const {TestUtils} = ChromeUtils.import("resource://testing-common/TestUtils.jsm");
+
+async function runTest(url, initialHTML, finalHTML) {
+ let iframe = document.createElement("iframe");
+ iframe.src = url;
+
+ let blockerPromise;
+ let promise = TestUtils.topicObserved("document-element-inserted", document => {
+ if (document !== iframe.contentDocument) {
+ return false;
+ }
+
+ blockerPromise = new Promise(resolve => {
+ setTimeout(resolve, 0);
+ }).then(() => {
+ return new Promise(resolve => setTimeout(resolve, 0));
+ }).then(() => {
+ return new Promise(resolve => setTimeout(resolve, 0));
+ });
+
+ is(document.documentElement.outerHTML, initialHTML,
+ "Should have initial HTML during document-element-inserted");
+ is(document.defaultView.wrappedJSObject.scriptRan, undefined,
+ "Script node should not have run");
+
+ document.blockParsing(blockerPromise);
+
+ return true;
+ }).then(([document]) => {
+ return document;
+ });
+
+ document.body.appendChild(iframe);
+
+ // Wait for document-element-inserted to fire.
+ let doc = await promise;
+ let win = doc.defaultView.wrappedJSObject;
+ let root = doc.documentElement;
+
+ // At this point, if the parser was successfully blocked, we should still
+ // have the initial skeleton HTML for the page.
+ is(root.outerHTML, initialHTML, "Should have initial HTML after document-element-inserted returns");
+ is(win.scriptRan, undefined, "Script node should still not have run");
+
+ await blockerPromise;
+
+ // Just after the promise that's blocking the parser fires, we shouldn't have
+ // returned to the main event loop, so we should still have the initial HTML.
+ is(root.outerHTML, initialHTML, "Should still have initial HTML");
+ is(win.scriptRan, undefined, "Script node should still not have run");
+
+ await new Promise(resolve => win.addEventListener("DOMContentLoaded", resolve, {once: true}));
+
+ // Parsing should have resumed, and we should have finished loading the document.
+ is(root.outerHTML, finalHTML, "Should have final HTML");
+ is(win.scriptRan, true, "Script node should have run");
+
+ iframe.remove();
+}
+
+add_task(async function() {
+ await runTest("http://mochi.test:8888/chrome/dom/base/test/file_inline_script.html",
+ '<html lang="en"></html>',
+ '<html lang="en"><head>\n <script>window.scriptRan = true;<\/script>\n <meta charset="utf-8">\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n\n\n</body></html>');
+
+ await runTest("http://mochi.test:8888/chrome/dom/base/test/file_inline_script.xhtml",
+ '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"></html>',
+ '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">\n<head>\n <script>window.scriptRan = true;<\/script>\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n</body>\n</html>');
+
+ await runTest("http://mochi.test:8888/chrome/dom/base/test/file_external_script.html",
+ '<html lang="en"></html>',
+ '<html lang="en"><head>\n <script src="file_script.js"><\/script>\n <meta charset="utf-8">\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n\n\n</body></html>');
+
+ await runTest("http://mochi.test:8888/chrome/dom/base/test/file_external_script.xhtml",
+ '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"></html>',
+ '<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">\n<head>\n <script src="file_script.js"><\/script>\n <title></title>\n</head>\n<body>\n <p>Hello Mochitest</p>\n</body>\n</html>');
+});
+
+add_task(async function test_cleanup() {
+ const TOPIC = "blocking-promise-destroyed";
+
+ const finalizationWitness = Cc["@mozilla.org/toolkit/finalizationwitness;1"]
+ .getService(Ci.nsIFinalizationWitnessService);
+
+ for (let url of ["http://mochi.test:8888/chrome/dom/base/test/file_inline_script.html",
+ "http://mochi.test:8888/chrome/dom/base/test/file_inline_script.xhtml"]) {
+ let iframe = document.createElement("iframe");
+ iframe.src = url;
+
+ // Create a promise that never resolves.
+ let blockerPromise = new Promise(() => {});
+
+ // Create a finalization witness so we can be sure that the promises
+ // have been collected before the end of the test.
+ let destroyedPromise = TestUtils.topicObserved(TOPIC);
+ let witness = finalizationWitness.make(TOPIC, url);
+ blockerPromise.witness = witness;
+
+ let insertedPromise = TestUtils.topicObserved("document-element-inserted", document => {
+ document.blockParsing(blockerPromise).witness = witness;
+
+ return true;
+ });
+
+ document.body.appendChild(iframe);
+ await insertedPromise;
+
+ // Clear the promise reference, destroy the document, and force GC/CC. This should
+ // trigger any potential leaks or cleanup issues.
+ blockerPromise = null;
+ witness = null;
+ iframe.remove();
+
+ Cu.forceGC();
+ Cu.forceCC();
+ Cu.forceGC();
+
+ // Make sure the blocker promise has been collected.
+ let [, data] = await destroyedPromise;
+ is(data, url, "Should have correct finalizer URL");
+ }
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_blocking_image.html b/dom/base/test/test_blocking_image.html
new file mode 100644
index 0000000000..64924b0dab
--- /dev/null
+++ b/dom/base/test/test_blocking_image.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1267075
+-->
+ <title>Test for Bug 1267075</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 onload="onLoad()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1267075">Mozilla Bug 1267075</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function onLoad() {
+ var iframe = document.createElement("iframe");
+ iframe.onload = function () {
+ info("iframe loaded");
+ function imgListener(img) {
+ return new Promise((resolve, reject) => {
+ img.addEventListener("load", () => reject());
+ img.addEventListener("error", () => resolve());
+ });
+ }
+
+ var doc = iframe.contentDocument;
+ var img = doc.createElement("img");
+ var img2 = doc.createElement("img");
+ var img3 = doc.createElement("img");
+
+ // image from HTTP should be blocked.
+ img.src = "http://example.com/tests/image/test/mochitest/shaver.png";
+ doc.body.appendChild(img);
+
+ imgListener(img).then(() => {
+ ok(true, "img shouldn't be loaded");
+
+ // `iframe` is a content iframe, and thus not in the same docgroup with
+ // us, which are a chrome-privileged test.
+ //
+ // Ensure the frame is laid out so that this cross-origin
+ // getComputedStyle call is guaranteed to work after bug 1440537.
+ iframe.getBoundingClientRect();
+
+ ok(img2.matches(":-moz-broken"), "should match ':-moz-broken' selector");
+
+ img2.src = "https://test.invalid";
+ doc.body.appendChild(img2);
+ return imgListener(img2);
+ }).then(() => {
+ ok(true, "img2 shouldn't be loaded");
+ ok(img2.matches(":-moz-broken"), "should match ':-moz-broken' selector");
+
+ // Now prepare for the next test, deny image.
+ return new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [["permissions.default.image", 2]]}, resolve)
+ });
+ }).then(() => {
+ // Now image is denied, loading image will be rejected with REJECT_TYPE,
+ // which will be mapped to :-moz-broken too.
+ img3.src = "https://example.com/tests/image/test/mochitest/shaver.png";
+ doc.body.appendChild(img3);
+ return imgListener(img3);
+ }).then(() => {
+ ok(true, "img3 shouldn't be loaded");
+
+ ok(img3.matches(":-moz-broken"), "should match ':-moz-broken' selector");
+
+ SimpleTest.finish();
+ }).catch((e) => {
+ // Expected early return
+ if(e === true) {
+ SimpleTest.finish();
+ return;
+ }
+ ok(false, "throwing " + e);
+ });
+ };
+
+ // file_blocking_image.html contains meta tag for CSP, which will block images from
+ // http.
+ iframe.src = "http://mochi.test:8888/chrome/dom/base/test/file_blocking_image.html";
+ document.getElementById("content").appendChild(iframe);
+}
+</script>
+</pre>
+<p id="display"></p>
+<div id="content">
+</div>
+
+</body> </html>
diff --git a/dom/base/test/test_bug1008126.html b/dom/base/test/test_bug1008126.html
new file mode 100644
index 0000000000..414f2727ec
--- /dev/null
+++ b/dom/base/test/test_bug1008126.html
@@ -0,0 +1,62 @@
+<!--
+2 Any copyright is dedicated to the Public Domain.
+3 http://creativecommons.org/publicdomain/zero/1.0/
+4 -->
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1008126
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1008126</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.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=1008126">Mozilla Bug 1008126</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+function translateChrome(uriStr) {
+ const { Cc, Ci } = SpecialPowers;
+ let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
+ let uri = ios.newURI(uriStr, null, ios.newURI(document.baseURI));
+ return chromeReg.convertChromeURL(uri).spec;
+}
+
+function runTest() {
+ var worker = new Worker("file_bug1008126_worker.js");
+
+ worker.onmessage = function(event) {
+ if (event.data.type == 'finish') {
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ ok(false, "Worker had an error: " + event.filename + ":" + event.lineno + ":" + event.colno + ": " + event.message);
+ SimpleTest.finish();
+ };
+
+ worker.postMessage(translateChrome("file_bug945152.jar"));
+}
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.mapped_arraybuffer.enabled", true]]}, function() {
+ SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], runTest);
+ });
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1016960.html b/dom/base/test/test_bug1016960.html
new file mode 100644
index 0000000000..d801a1dba5
--- /dev/null
+++ b/dom/base/test/test_bug1016960.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1016960
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1016960</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1016960 **/
+
+ var chromeWindow = window.browsingContext.topChromeWindow.open("chrome://mochitests/content/chrome/dom/base/test/file_empty.html", "1016960", "chrome");
+ ok(chromeWindow.isChromeWindow, "A chrome window should return true for .isChromeWindow.");
+ chromeWindow.close();
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1016960">Mozilla Bug 1016960</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1022229.html b/dom/base/test/test_bug1022229.html
new file mode 100644
index 0000000000..7663cc22d0
--- /dev/null
+++ b/dom/base/test/test_bug1022229.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1022229
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1022229</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 postMessage between sandboxed iframe and non-sandboxed window.
+ **/
+ SimpleTest.waitForExplicitFinish();
+ function go() {
+ var ifr = document.createElement('iframe');
+
+ ifr.setAttribute('src', 'iframe_main_bug1022229.html');
+ document.body.appendChild(ifr);
+ }
+
+ </script>
+</head>
+<body onload="go()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1022229">Mozilla Bug 1022229</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1025933.html b/dom/base/test/test_bug1025933.html
new file mode 100644
index 0000000000..e578ebef20
--- /dev/null
+++ b/dom/base/test/test_bug1025933.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1025933
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1025933</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 1025933 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function test() {
+ var iframe = document.createElement('iframe');
+ iframe.srcdoc = '<div id="content"> <div id="host"></div </div>';
+
+ iframe.onload = function() {
+ var s = iframe.contentDocument.getElementById("host").attachShadow({mode: 'open'});
+ s.innerHTML = '<div style="width:100px;height:100px;background:red"></div>';
+ var el = s.firstElementChild;
+ is(el.clientWidth, 100);
+ is(el.clientHeight, 100);
+ SimpleTest.finish();
+ }
+
+ document.body.appendChild(iframe);
+ }
+
+ </script>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1025933">Mozilla Bug 1025933</a>
+<p id="display"></p>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1037687.html b/dom/base/test/test_bug1037687.html
new file mode 100644
index 0000000000..62f886c837
--- /dev/null
+++ b/dom/base/test/test_bug1037687.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1037687
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1037687</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=1037687">Mozilla Bug 1037687</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<script type="application/javascript">
+ /** Test for Bug 1037687 **/
+ SimpleTest.waitForExplicitFinish();
+ window.onload = function() {
+ // This test loads in an iframe, to ensure that the element instance is
+ // loaded with the correct value of the preference.
+ let iframe = document.createElement("iframe");
+ iframe.src = "test_bug1037687_subframe.html";
+ document.body.appendChild(iframe);
+ };
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1037687_subframe.html b/dom/base/test/test_bug1037687_subframe.html
new file mode 100644
index 0000000000..4258f772b6
--- /dev/null
+++ b/dom/base/test/test_bug1037687_subframe.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script type="application/javascript">
+ var SimpleTest = window.parent.SimpleTest;
+ var ok = window.parent.ok;
+ var is = window.parent.is;
+
+ var host;
+ var embed;
+ var object;
+ var iframe;
+ var resourceLoadCount = 0;
+
+ function resourceLoaded(event) {
+ ++resourceLoadCount;
+ ok(true, event.target + " got " + event.load);
+ if (resourceLoadCount == 3) {
+ SimpleTest.finish();
+ }
+ }
+
+ function createResource(sr, type) {
+ var el = document.createElement(type);
+ var attrName = type == "object" ? "data" : "src";
+ el.setAttribute(attrName, "file_mozfiledataurl_img.jpg");
+ el.onload = resourceLoaded;
+ var info = document.createElement("div");
+ info.textContent = type;
+ sr.appendChild(info);
+ sr.appendChild(el);
+ }
+
+ function test() {
+ host = document.getElementById("host");
+ let sr = host.attachShadow({mode: 'open'});
+ embed = createResource(sr, "embed");
+ object = createResource(sr, "object");
+ iframe = createResource(sr, "iframe");
+ }
+</script>
+</head>
+<body onload="test()">
+<div id="host"></div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1043106.html b/dom/base/test/test_bug1043106.html
new file mode 100644
index 0000000000..42d6cfff57
--- /dev/null
+++ b/dom/base/test/test_bug1043106.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1043106
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1043106</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=1043106">Mozilla Bug 1043106</a>
+ <iframe id="iframe"></iframe>
+ <script type="application/javascript">
+
+var storage;
+
+window.addEventListener("storage", function (event) {
+ is(event.storageArea, storage, "The storageArea is correct");
+ storage.removeItem("a");
+ runTests();
+});
+
+var tests = [ { key: 'localStorage', storage: localStorage },
+ { key: 'sessionStorage', storage: sessionStorage } ];
+function runTests() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var t = tests.shift();
+ storage = t.storage;
+
+ var ifr = document.getElementById("iframe");
+ ifr.srcdoc = "<script>"+ t.key + ".setItem(\"a\",\"b\");</"+"script>";
+}
+
+SimpleTest.waitForExplicitFinish();
+runTests();
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1057176.html b/dom/base/test/test_bug1057176.html
new file mode 100644
index 0000000000..e9e516ac1e
--- /dev/null
+++ b/dom/base/test/test_bug1057176.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1057176
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1057176</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 1057176 **/
+ var doc = document.implementation.createDocument(null, null);
+ var elem = doc.createElementNS("http://www.w3.org/1999/xhtml", "input");
+ elem.pattern = "abc";
+ elem.value = "def";
+ ok(!elem.validity.valid, '"def" should not match the pattern "abc"');
+ elem.value = "abc";
+ ok(elem.validity.valid, '"abc" should match the pattern "abc"');
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1057176">Mozilla Bug 1057176</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1060938.html b/dom/base/test/test_bug1060938.html
new file mode 100644
index 0000000000..451ed0d6fb
--- /dev/null
+++ b/dom/base/test/test_bug1060938.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1060938
+-->
+ <head>
+ <meta charset="utf-8">
+ <title> Test for Bug 1060938 </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=1060938"> Mozilla Bug 1060938 </a>
+ <p id="display"></p>
+
+ <pre id="test">
+ <script type="application/javascript">
+
+ /** Test for Bug 1060938 **/
+ // test: Element.removeAttributeNode()
+
+ parent = document.getElementsByTagName("p")[0];
+ parent.setAttributeNS("www.test1.com", "ID", "Test1");
+ parent.setAttributeNS("www.test2.com", "Class", "Test2");
+ parent.setAttribute("id", "www.test3.com");
+ parent.className = "www.test4.com";
+
+ allAttributes = parent.attributes;
+
+ function removeAttr(iter){
+ var removed_attribute = allAttributes[0];
+ is(removed_attribute, parent.removeAttributeNode(removed_attribute),
+ "(" + iter + ")" + " Returned attribute and remove attribute should be same.");
+ }
+
+ removeAttr(1);
+ removeAttr(2);
+ removeAttr(3);
+ removeAttr(4);
+
+ </script>
+ </body>
+</html>
diff --git a/dom/base/test/test_bug1064481.html b/dom/base/test/test_bug1064481.html
new file mode 100644
index 0000000000..9ce32f4d49
--- /dev/null
+++ b/dom/base/test/test_bug1064481.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1064481
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1064481</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=1064481">Mozilla Bug 1064481</a>
+ <iframe id="iframe"></iframe>
+ <script type="application/javascript">
+
+var a = new URLSearchParams();
+
+a.set('foobar', 'a\nb');
+is(a.toString(), 'foobar=a%0Ab', "Bug fixed");
+
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1070015.html b/dom/base/test/test_bug1070015.html
new file mode 100644
index 0000000000..5debff4dc0
--- /dev/null
+++ b/dom/base/test/test_bug1070015.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1070015
+-->
+<head>
+ <title>Test for Bug 1070015</title>
+ <script type="application/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=1070015">Mozilla Bug 1070015</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="attrTest1" testAttr="testValue1"></div>
+<div id="attrTest2" testAttr="testValue2"></div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1070015 **/
+
+function testRemoveAttribute() {
+ var attrTest1 = document.getElementById("attrTest1");
+ var attr1 = attrTest1.getAttributeNode("testAttr");
+
+ var attrTest2 = document.getElementById("attrTest2");
+ var attr2 = attrTest2.getAttributeNode("testAttr");
+
+ ok(attrTest1.hasAttribute("testAttr"), "First object should have attribute");
+ ok(attrTest2.hasAttribute("testAttr"), "Second object should have attribute");
+
+ try {
+ attrTest1.removeAttributeNode(attr2);
+ ok(false, "Should throw when removing from the different element");
+ } catch (e) {
+ ok(true, "Should throw when removing from the different element");
+ }
+
+ ok(attrTest1.hasAttribute("testAttr"), "Object should not remove attribute which not belongs to it");
+ ok(attrTest2.hasAttribute("testAttr"), "Object should not be changed");
+
+ attrTest1.removeAttributeNode(attr1);
+ ok(!attrTest1.hasAttribute("testAttr"), "Object should remove its attribute");
+}
+testRemoveAttribute();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1075702.html b/dom/base/test/test_bug1075702.html
new file mode 100644
index 0000000000..a3842a21a5
--- /dev/null
+++ b/dom/base/test/test_bug1075702.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1075702
+-->
+<head>
+ <meta charset="utf-8">
+ <title> Test for Bug 1075702 </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=1075702"> Mozilla Bug 1075702 </a>
+<p id="display"></p>
+
+<pre id="test">
+<script type="application/javascript">
+
+ /** Test for Bug 1075702 **/
+ // test: Element.removeAttributeNode()
+
+ var a1 = document.createAttribute("aa");
+ a1.nodeValue = "lowercase";
+
+ var a2 = document.createAttributeNS("", "AA");
+ a2.nodeValue = "UPPERCASE";
+
+ document.documentElement.setAttributeNode(a1);
+ document.documentElement.setAttributeNode(a2);
+
+ is(document.documentElement.getAttributeNS("", "aa"), "lowercase", "Should be lowercase!");
+ is(document.documentElement.getAttributeNS("", "AA"), "UPPERCASE", "Should be UPPERCASE!");
+
+ var a3 = document.createAttribute("AA");
+ a3.nodeValue = "UPPERCASE AGAIN";
+ document.documentElement.setAttributeNode(a3);
+
+ is(document.documentElement.getAttributeNS("", "aa"), "UPPERCASE AGAIN",
+ "Should be UPPERCASE AGAIN!");
+ is(document.documentElement.getAttributeNS("", "AA"), "UPPERCASE", "Should be UPPERCASE!");
+
+ var removedNodeAccordingToEvent;
+
+ function mutationHandler(aEvent) {
+ removedNodeAccordingToEvent = aEvent.relatedNode;
+ }
+
+ var test1 = document.createElement("div");
+ test1.setAttribute("x", "y");
+ removedNodeAccordingToEvent = null;
+
+ function testremoveNamedItemNS() {
+ test1.addEventListener("DOMAttrModified", mutationHandler, true);
+ var removedNodeAccordingToRemoveNamedItemNS = test1.attributes.removeNamedItemNS(null, "x");
+ test1.removeEventListener("DOMAttrModified", mutationHandler, true);
+ is(removedNodeAccordingToEvent, removedNodeAccordingToRemoveNamedItemNS, "Node removed according to event is not same as node removed by removeNamedItemNS.");
+ }
+
+ testremoveNamedItemNS();
+
+ var test2 = document.createElement("div");
+ test2.setAttribute("x", "y");
+ removedNodeAccordingToEvent = null;
+
+ function testremoveNamedItem() {
+ test2.addEventListener("DOMAttrModified", mutationHandler, true);
+ var removedNodeAccordingToRemoveNamedItem = test2.attributes.removeNamedItem("x");
+ test2.removeEventListener("DOMAttrModified", mutationHandler, true);
+ is(removedNodeAccordingToEvent, removedNodeAccordingToRemoveNamedItem, "Node removed according to event is not same as node removed by removeNamedItem.");
+ }
+
+ testremoveNamedItem();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1091883.html b/dom/base/test/test_bug1091883.html
new file mode 100644
index 0000000000..fd2558d89c
--- /dev/null
+++ b/dom/base/test/test_bug1091883.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1091883
+-->
+<head>
+ <meta charset="utf-8">
+ <meta name="referrer" content="origin-when-cross-origin">
+ <title>Test for Bug 1091883</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1091883">Mozilla Bug 1091883</a></p>
+<h2>Results</h2>
+<pre id="results">Running...</pre>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+var origins = [
+ "http://mochi.test:8888", "http://example.com", "http://example.org"];
+var numOrigins = origins.length;
+
+// For each combination of (frame, subframe, target) origins, this test
+// includes a "frame" that includes a "subframe"; and then this test
+// navigates this "subframe" to the "target". Both the referrer and
+// the triggering principal are this test, i.e., "http://mochi.test:8888".
+// Since the referrer policy is origin-when-cross-origin, we expect to have
+// a full referrer if and only if the target is also "http://mochi.test:8888";
+// in all other cases, the referrer needs to be the origin alone.
+var numTests = numOrigins * numOrigins * numOrigins;
+
+// Helpers to look up the approriate origins for a given test number.
+function getFrameOrigin(i) {
+ return origins[(i / (numOrigins * numOrigins)) | 0];
+}
+function getSubframeOrigin(i) {
+ return origins[((i / numOrigins) | 0) % 3];
+}
+function getTargetOrigin(i) {
+ return origins[i % 3];
+}
+
+// Create the frames, and tell them which subframes to load.
+for (let i = 0; i < numTests; i++) {
+ var frame = document.createElement("iframe");
+ frame.src = getFrameOrigin(i) +
+ "/tests/dom/base/test/file_bug1091883_frame.html#" +
+ getSubframeOrigin(i);
+ document.body.appendChild(frame);
+}
+
+// Navigate all subframes to the target.
+window.onload = function() {
+ for (let i = 0; i < numTests; i++) {
+ frames[i].frames[0].location = getTargetOrigin(i) +
+ "/tests/dom/base/test/file_bug1091883_target.html#" + i;
+ }
+};
+
+// Check referrer messages from the target.
+var results = {};
+function makeResultsKey(i) {
+ return i + ": " + getFrameOrigin(i) + " | " + getSubframeOrigin(i) + " -> " +
+ getTargetOrigin(i);
+}
+window.addEventListener("message", function(event) {
+ var out = event.data.split(" ");
+ var referrer = out[0];
+ var testRun = +out[1];
+ results[makeResultsKey(testRun)] = referrer;
+ if (event.origin == "http://mochi.test:8888") {
+ is(referrer.split("?")[0],
+ "http://mochi.test:8888/tests/dom/base/test/test_bug1091883.html",
+ "must be full referrer");
+ } else {
+ is(referrer, "http://mochi.test:8888/", "must be origin referrer");
+ }
+ if (Object.keys(results).length == numTests) {
+ document.getElementById("results").textContent =
+ JSON.stringify(results, null, 4);
+ SimpleTest.finish();
+ }
+});
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug1100912.html b/dom/base/test/test_bug1100912.html
new file mode 100644
index 0000000000..95913e8cdd
--- /dev/null
+++ b/dom/base/test/test_bug1100912.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1100912
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1100912</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 1100912 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function runTests() {
+ win = window.open("file_bug1100912.html", "");
+ }
+
+ function didRunTests() {
+ setTimeout("SimpleTest.finish()");
+ }
+
+ </script>
+</head>
+<body onload="SimpleTest.waitForFocus(runTests)">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1100912">Mozilla Bug 1100912</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1101364.html b/dom/base/test/test_bug1101364.html
new file mode 100644
index 0000000000..f3794d3dd0
--- /dev/null
+++ b/dom/base/test/test_bug1101364.html
@@ -0,0 +1,93 @@
+<!DOCTYPE>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1101364
+-->
+<head>
+<title>Test for Bug 1101364</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style>
+ #test1 {
+ user-select: none;
+ }
+
+ #testDiv, #test2 {
+ user-select: text;
+ }
+ </style>
+</head>
+<body id='body'>
+
+<iframe id="test1" srcdoc="<h1 id='test1' style='user-select:none'>Header</h1><div id='testDiv'>test1</div>"></iframe>
+<iframe id="test2" srcdoc="<div contenteditable id='test2'>AAA<span id='test2Inner'>BBB</span></div>"></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async () => {
+ await (async () => {
+ const iframe = document.getElementById("test1");
+ iframe.focus();
+ const docShell = SpecialPowers.wrap(iframe.contentWindow).docShell;
+
+ docShell.doCommand("cmd_selectAll");
+ info(
+ "Waiting for getting screenshot of \"Select All\" without contenteditable..."
+ );
+ const withoutContenteditable = await snapshotWindow(iframe.contentWindow);
+
+ iframe.contentDocument
+ .getElementById("testDiv")
+ .setAttribute("contentEditable", true);
+ docShell.doCommand("cmd_selectAll");
+ info(
+ "Waiting for getting screenshot of \"Select All\" in contenteditable..."
+ );
+ const withContenteditable = await snapshotWindow(iframe.contentWindow);
+ const result =
+ compareSnapshots(withoutContenteditable, withContenteditable, true);
+ ok(
+ result[0],
+ `Select all should look identical\ngot: ${
+ result[2]
+ }\nexpected: ${result[1]}`
+ );
+ })();
+
+ await (async () => {
+ const iframe = document.getElementById("test2");
+ iframe.focus();
+ iframe.contentDocument.querySelector("div[contenteditable]").focus();
+ const docShell = SpecialPowers.wrap(iframe.contentWindow).docShell;
+ const test2Inner = iframe.contentDocument.getElementById("test2Inner");
+ test2Inner.style.MozUserSelect = "text";
+ docShell.doCommand("cmd_selectAll");
+ info(
+ "Waiting for getting screenshot of \"Select All\" in contenteditable (use-select: text)..."
+ );
+ const withoutUserSelect = await snapshotWindow(iframe.contentWindow);
+
+ test2Inner.style.MozUserSelect = "none";
+ docShell.doCommand("cmd_selectAll");
+ info(
+ "Waiting for getting screenshot of \"Select All\" in contenteditable (use-select: none)..."
+ );
+ const withUserSelect = await snapshotWindow(iframe.contentWindow);
+ const result = compareSnapshots(withoutUserSelect, withUserSelect, true);
+ ok(
+ result[0],
+ `Editable fields should ignore user select style\ngot: ${
+ result[2]
+ }\nexpected: ${result[1]}`
+ );
+ })();
+
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1118689.html b/dom/base/test/test_bug1118689.html
new file mode 100644
index 0000000000..e073b6fcfa
--- /dev/null
+++ b/dom/base/test/test_bug1118689.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1118689
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1118689</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 1118689 **/
+ SimpleTest.requestFlakyTimeout("Just need some random timeout.");
+
+ function test() {
+ // check that load event doesn't keep up being dispatched if
+ // window has been closed.
+ var win = window.open('data:text/html,<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP" onload="this.src = this.src">',
+ "", "height=100,width=100");
+ setTimeout(function() {
+ win.close();
+ SimpleTest.finish();
+ }, 2500);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+
+ </script>
+</head>
+<body onload="test();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1118689">Mozilla Bug 1118689</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1120222.html b/dom/base/test/test_bug1120222.html
new file mode 100644
index 0000000000..f4f1bf8faa
--- /dev/null
+++ b/dom/base/test/test_bug1120222.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1120222
+-->
+<head>
+ <meta charset=utf-8>
+ <title>Test document-title-changed observer</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ const obsSvc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+
+ const observer = {
+ observe: (aSubject, aTopic, aData) => {
+ if (aTopic === "document-title-changed") {
+ SimpleTest.ok(true, "document-title-changed was received.");
+ obsSvc.removeObserver(observer, "document-title-changed");
+ SimpleTest.finish();
+ }
+ },
+ };
+
+ obsSvc.addObserver(observer, "document-title-changed");
+ document.title = "Changed title";
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1126851.html b/dom/base/test/test_bug1126851.html
new file mode 100644
index 0000000000..117aabb530
--- /dev/null
+++ b/dom/base/test/test_bug1126851.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1126851
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1126851</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 1126851 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function runTest() {
+ win = window.open("about:blank", "");
+ win.onload = function() {
+ win.onunload = function() {
+ ok(true, "got unload");
+ win.close();
+ SimpleTest.finish();
+ }
+ win.onresize = function() {
+ win.location.reload();
+ }
+ win.document.dispatchEvent(new win.Event("resize", { bubbles: true }));
+ }
+ }
+
+
+ </script>
+</head>
+<body onload="runTest()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1126851">Mozilla Bug 1126851</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug116083.html b/dom/base/test/test_bug116083.html
new file mode 100644
index 0000000000..a1736d6cce
--- /dev/null
+++ b/dom/base/test/test_bug116083.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=116083
+-->
+<head>
+ <title>Test for Bug 116083</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=116083">Mozilla Bug 116083</a>
+<div id="content">
+<div style="white-space: pre">foo bar</div>
+<div style="white-space: pre-wrap">foo bar</div>
+<div style="white-space: pre-line">foo bar</div>
+<div style="white-space: -moz-pre-space">foo bar</div>
+<div style="white-space: pre" data-collapse-selection-to-child-and-extend>foo bar</div>
+<div style="white-space: pre-wrap" data-collapse-selection-to-child-and-extend>foo bar</div>
+<div style="white-space: pre-line" data-collapse-selection-to-child-and-extend>foo bar</div>
+<div style="white-space: -moz-pre-space" data-collapse-selection-to-child-and-extend>foo bar</div>
+<div data-result="bar baz"><span style="white-space: pre">bar </span>baz</div>
+<div data-result="bar baz"><span style="white-space: pre-wrap">bar </span>baz</div>
+<div data-result="bar baz"><span style="white-space: pre-line">bar </span>baz</div>
+<div data-result="bar baz"><span style="white-space: -moz-pre-space">bar </span>baz</div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-wrap"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-wrap" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-line"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-line" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space"><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo&#10;bar&#10;baz&#10;qux"><div>foo<br></div><span>bar<br>baz<br>qux</span></div>
+<div data-result="foo&#10;bar&#10;baz&#10;qux" contenteditable><div>foo<br></div><span>bar<br>baz<br>qux</span></div>
+<div data-result="foo&#10;&#10;"><div>foo</div><span><br></span></div>
+<div data-result="foo&#10;&#10;" contenteditable><div>foo</div><span><br></span></div>
+<div data-result="foo&#10;&#10;bar"><div>foo</div><span><br></span><div>bar</div></div>
+<div data-result="foo&#10;&#10;bar" contenteditable><div>foo</div><span><br></span><div>bar</div></div>
+<div data-result="foo&#10;bar&#10;"><div>foo</div><span>bar<br></span></div>
+<div data-result="foo&#10;bar" contenteditable><div>foo</div><span>bar<br></span></div>
+<div data-result="foo&#10;bar&#10;baz"><div>foo</div><span>bar<br></span><div>baz</div></div>
+<div data-result="foo&#10;bar&#10;baz" contenteditable><div>foo</div><span>bar<br></span><div>baz</div></div>
+<div data-result="&#10;&#10;foo"><div><br><br><div>foo</div></div></div>
+<div data-result="&#10;&#10;foo" contenteditable><div><br><br><div>foo</div></div></div>
+<div data-result="foo&#10;bar"><div>foo<br>bar</div></div>
+<div data-result="foo&#10;bar" contenteditable><div>foo<br>bar</div></div>
+<div data-result="foo&#10;bar&#10;"><div>foo<br>bar<br></div></div>
+<div data-result="foo&#10;bar" contenteditable><div>foo<br>bar<br></div></div>
+<div data-result="&#10;foo bar&#10;">foo bar</div>
+</div>
+<script type="application/javascript">
+
+const Cc = SpecialPowers.Cc;
+const Ci = SpecialPowers.Ci;
+
+function hasExpectedFlavors() {
+ var cb = Cc["@mozilla.org/widget/clipboard;1"].
+ getService(Ci.nsIClipboard);
+
+ ok(cb.hasDataMatchingFlavors(["text/plain"], cb.kGlobalClipboard),
+ "The clipboard has text/plain");
+
+ ok(cb.hasDataMatchingFlavors(["text/html"], cb.kGlobalClipboard),
+ "The clipboard has text/html");
+
+ if (navigator.appVersion.includes("Win")) {
+ ok(cb.hasDataMatchingFlavors(["application/x-moz-nativehtml"], cb.kGlobalClipboard),
+ "The clipboard has application/x-moz-nativehtml");
+ }
+}
+
+function collapseSelectionToChildAndExtend(divElement) {
+ is(divElement.childNodes.length, 1, "Expected exactly one child node.");
+ var textChildNode = divElement.childNodes[0];
+ getSelection().collapse(textChildNode);
+ getSelection().extend(textChildNode, divElement.textContent.length);
+}
+
+function selectDependingOnAttributes(divElement) {
+ if (divElement.hasAttribute("data-collapse-selection-to-child-and-extend")) {
+ // Selecting text as follow comes closest to user behaviour.
+ collapseSelectionToChildAndExtend(divElement);
+ } else {
+ getSelection().selectAllChildren(divElement);
+ }
+}
+
+function nextTest() {
+ var div = document.querySelector("#content>div");
+ if (!div) {
+ SimpleTest.finish();
+ return;
+ }
+
+ selectDependingOnAttributes(div);
+
+ var expected = div.hasAttribute("data-result") ?
+ div.getAttribute("data-result") :
+ div.textContent;
+
+ SimpleTest.waitForClipboard(expected, function() {
+ synthesizeKey("C", {accelKey: true});
+ }, function() {
+ ok(true, div.getAttribute("style") + " passed");
+ hasExpectedFlavors();
+ div.remove();
+ nextTest();
+ }, function() {
+ ok(false, "failed to copy the expected content to the clipboard");
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(nextTest);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1163743.html b/dom/base/test/test_bug1163743.html
new file mode 100644
index 0000000000..1965909284
--- /dev/null
+++ b/dom/base/test/test_bug1163743.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This checks if the origin-when-crossorigin policy works.
+https://bugzilla.mozilla.org/show_bug.cgi?id=1163743
+-->
+
+<head>
+ <meta charset="utf-8">
+ <title>Test policies for Bug 1163743</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="referrerHelper.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * testing legacy support for origin-when-crossorigin (1163743)
+ */
+var tests = (function*() {
+ var iframe = document.getElementById("testframe");
+ const sjs = "/tests/dom/base/test/bug704320.sjs?action=generate-policy-test";
+
+ // origin when crossorigin (trimming whitespace)
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape(' origin-when-crossorigin');
+ yield checkIndividualResults("origin-when-cross-origin", ["origin", "full"]);
+
+ // complete.
+ SimpleTest.finish();
+})();
+
+</script>
+</head>
+
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug1165501.html b/dom/base/test/test_bug1165501.html
new file mode 100644
index 0000000000..d0f98a9b05
--- /dev/null
+++ b/dom/base/test/test_bug1165501.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Spot test to see if newer meta-referrer policy is used
+https://bugzilla.mozilla.org/show_bug.cgi?id=1165501
+-->
+
+<head>
+ <meta charset="utf-8">
+ <title>Test policies for Bug 1165501</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="referrerHelper.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * testing if policy is overwritten if there are two meta statements (1165501)
+ * XXX: would be nice to test this with CSP and meta as well
+ */
+var tests = (function*() {
+ var iframe = document.getElementById("testframe");
+ const sjs = "/tests/dom/base/test/bug704320.sjs?action=generate-policy-test";
+
+ // setting first unsafe-url and then origin - origin shall prevail
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape('origin')+ "&wrongPolicy=" + escape('unsafe-url');
+ yield checkIndividualResults("unsafe-url then origin", ["origin"]);
+
+ // setting first no-referrer and then default - default shall prevail
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape('default')+ "&wrongPolicy=" + escape('no-referrer');
+ yield checkIndividualResults("no-referrer then default", ["full"]);
+
+
+ // complete.
+ SimpleTest.finish();
+})();
+
+</script>
+</head>
+
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug1187157.html b/dom/base/test/test_bug1187157.html
new file mode 100644
index 0000000000..d96c11e635
--- /dev/null
+++ b/dom/base/test/test_bug1187157.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1187157
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1187157</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=1187157">Mozilla Bug 1187157</a>
+<form id="a"><input name="b" type="file"/></form>
+
+<script type="text/javascript">
+ var obj = new FormData(document.getElementById('a')).get('b');
+ ok(obj instanceof File, "This should return a File");
+ is(obj.size, 0, "Size should be 0");
+ is(obj.name, "", "Name should be the empty string.");
+ is(
+ obj.type,
+ "application/octet-stream",
+ "Type should be application/octet-stream"
+ );
+
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug1198095.html b/dom/base/test/test_bug1198095.html
new file mode 100644
index 0000000000..bcc005d897
--- /dev/null
+++ b/dom/base/test/test_bug1198095.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1198095
+-->
+ <title>Test for Bug 1198095</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=1198095">Mozilla Bug 1198095</a>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var fileData1 = '1234567890';
+var fileData2 = '43210';
+var r, firstBlob;
+
+var openerURL = SimpleTest.getTestFileURL("file_bug1198095.js");
+
+var opener = SpecialPowers.loadChromeScript(openerURL);
+opener.addMessageListener("file.opened", onFileOpened);
+opener.addMessageListener("file.modified", onFileModified);
+opener.sendAsyncMessage("file.open", fileData1);
+
+function onLoadEnd1(e) {
+ e.target.removeEventListener('loadend', onLoadEnd1);
+
+ is(e.target, r, "Target and r are ok");
+ is(e.target.readyState, FileReader.DONE, "The file has been read.");
+ ok(e.target.result instanceof ArrayBuffer, "The result is an ArrayBuffer");
+
+ var view = new Uint8Array(e.target.result);
+ is(view.length, fileData1.length, "File data length matches");
+ for (var i = 0; i < fileData1.length; ++i) {
+ is(String.fromCharCode(view[i]), fileData1[i], "Byte matches");
+ }
+
+ opener.sendAsyncMessage("file.modify", fileData2);
+}
+
+function onError1(e) {
+ ok(false, "This method should not be called - error1!");
+}
+
+function onError2(e) {
+ e.target.removeEventListener('error', onError2);
+ SimpleTest.finish();
+}
+
+function onFileOpened(blob) {
+ firstBlob = blob;
+ r = new FileReader();
+ r.addEventListener("loadend", onLoadEnd1);
+ r.addEventListener("error", onError1);
+ r.readAsArrayBuffer(firstBlob);
+}
+
+function onFileModified(blob) {
+ r.removeEventListener('error', onError1);
+ r.addEventListener("error", onError2);
+ r.readAsArrayBuffer(firstBlob);
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body> </html>
diff --git a/dom/base/test/test_bug1222633.html b/dom/base/test/test_bug1222633.html
new file mode 100644
index 0000000000..f2f83145de
--- /dev/null
+++ b/dom/base/test/test_bug1222633.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1222633
+-->
+<head>
+ <title>Test for Bug 1222633</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=1222633">Mozilla Bug 1222633</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1222633 **/
+
+function testPreloadEvent(url, crossorigin, expectLoad) {
+ return new Promise((resolve) => {
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "preload");
+ link.setAttribute("href", url);
+ link.setAttribute("as", "fetch");
+ if (crossorigin) {
+ link.setAttribute("crossorigin", "");
+ }
+
+ link.addEventListener("load", () => {
+ ok(expectLoad, "not expecting load event for " + url);
+ link.remove();
+ resolve();
+ });
+ link.addEventListener("error", () => {
+ ok(!expectLoad, "not expecting error event for " + url);
+ link.remove();
+ resolve();
+ });
+ document.head.appendChild(link);
+ });
+}
+
+function testChangePrefetchToPreload(url) {
+ return new Promise((resolve) => {
+ var preloaded = false;
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "prefetch");
+ link.setAttribute("href", url);
+ link.setAttribute("as", "fetch");
+
+ link.addEventListener("load", () => {
+ ok(preloaded, "this will happen only on a preload");
+ ok(true, "not expecting load event for " + url);
+ link.remove();
+ resolve();
+ });
+ link.addEventListener("error", () => {
+ ok(false, "not expecting error event for " + url);
+ link.remove();
+ resolve();
+ });
+ document.head.appendChild(link);
+ preloaded = true;
+ link.setAttribute("rel", "preload");
+ })
+};
+
+const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs");
+const SAME_ORIGIN = "http://mochi.test:8888" + SJS_PATH;
+const CROSS_ORIGIN = "http://example.com" + SJS_PATH;
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [["network.preload", true]]})
+
+// test same origin
+.then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, true))
+.then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, false))
+.then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPreloadEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, false))
+
+// test cross origin without CORS
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, true))
+
+// test cross origin by redirection without CORS
+.then(() => testPreloadEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=200&cacheControl=no-cache", false, true))
+.then(() => testPreloadEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=404&cacheControl=no-cache", false, true))
+.then(() => testPreloadEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPreloadEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=404&cacheControl=max-age%3D120", false, true))
+
+// test cross origin with CORS request but no CORS response
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", true, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", true, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", true, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", true, true))
+
+// test cross origin with CORS request and CORS response
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache&allowOrigin=*", true, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache&allowOrigin=*", true, false))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120&allowOrigin=*", true, true))
+.then(() => testPreloadEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120&allowOrigin=*", true, false))
+.then(() => testChangePrefetchToPreload(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
+
+.catch((err) => ok(false, "promise rejected: " + err))
+.then(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1222633_link_update.html b/dom/base/test/test_bug1222633_link_update.html
new file mode 100644
index 0000000000..07c6662085
--- /dev/null
+++ b/dom/base/test/test_bug1222633_link_update.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1222633
+-->
+<head>
+ <title>Test for Bug 1222633</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=1222633">Mozilla Bug 1222633</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1222633 **/
+
+// Test changing as attribute from an empty value to "foo" to "image". The empty value and "foo" will
+// not trigger any event and "image" should trigger an load event.
+function testPreloadEventAsAttributeChange(url) {
+ return new Promise((resolve) => {
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "preload");
+ link.setAttribute("href", url);
+
+ link.addEventListener("load", () => {
+ ok(link.as == "image", "Only image will trigger a load event");
+ link.remove();
+ resolve();
+ });
+ link.addEventListener("error", () => {
+ ok(false, "We should not get an error event.");
+ });
+
+ document.head.appendChild(link);
+ link.setAttribute("as", "foo");
+ link.setAttribute("as", "image");
+ });
+}
+
+function testPreloadEventAttributeChange(url, attr, invalidValue, validValue) {
+ return new Promise((resolve) => {
+ var count = 0;
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "preload");
+ link.setAttribute("href", url);
+ link.setAttribute("as", "image");
+
+ link.setAttribute(attr, invalidValue);
+
+ let firedLoad = false;
+ link.addEventListener("load", () => {
+ ok(!firedLoad, "expecting first load event for " + url);
+ firedLoad = true;
+ link.remove();
+ resolve();
+ });
+ link.addEventListener("error", () => {
+ ok(false, "shouldn't fire error events");
+ });
+ document.head.appendChild(link);
+ SimpleTest.executeSoon(function() {
+ ok(!firedLoad, "Invalid value shouldn't fire load event");
+ link.setAttribute(attr, validValue);
+ })
+ });
+}
+
+function testPreloadEventSetCrossOrigin(url) {
+ return new Promise((resolve) => {
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "preload");
+ link.setAttribute("href", url);
+ link.setAttribute("as", "fetch");
+ count = 0;
+
+ link.addEventListener("load", () => {
+ count++;
+ if ((count == 1) || (count == 3) || (count == 5)) {
+ ok(true, "expecting " + count + ". load event for " + url);
+ } else {
+ ok(false, "expecting " + count + ". event for " + url);
+ }
+ if ((count == 1) || (count == 3)) {
+ link.setAttribute("crossorigin", "");
+ } else {
+ link.remove();
+ resolve();
+ }
+ });
+
+ link.addEventListener("error", () => {
+ count++;
+ if ((count == 2) || (count == 4)) {
+ ok(true, "expecting " + count + ". error event for " + url);
+ } else {
+ ok(false, "expecting " + count + ". error event for " + url);
+ }
+ link.removeAttribute("crossorigin");
+ });
+ document.head.appendChild(link);
+ });
+}
+
+const IMAGE_PATH = window.location.pathname.replace(/[^/]+$/, "file_mozfiledataurl_img.jpg");
+const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs");
+const SAME_ORIGIN = "http://mochi.test:8888";
+const CROSS_ORIGIN = "http://example.com";
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [["network.preload", true]]})
+
+// Test changing as parameter from a wrong to a correct one.
+.then(() => testPreloadEventAsAttributeChange(SAME_ORIGIN + IMAGE_PATH))
+// Test changing type parameter from a wrong to a correct one for given as parameter.
+.then(() => testPreloadEventAttributeChange(SAME_ORIGIN + IMAGE_PATH, "type", "text/vtt", "image/png"))
+// Test changing media parameter from a wrong to a correct one.
+.then(() => testPreloadEventAttributeChange(SAME_ORIGIN + IMAGE_PATH, "media", "foo", "all"))
+// Test changing crossorigin parameter.
+.then(() => testPreloadEventSetCrossOrigin(CROSS_ORIGIN + SJS_PATH + "?statusCode=404&cacheControl=max-age%3D120&allowOrigin=*"))
+
+.catch((err) => ok(false, "promise rejected: " + err))
+.then(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1238440.html b/dom/base/test/test_bug1238440.html
new file mode 100644
index 0000000000..528b337c00
--- /dev/null
+++ b/dom/base/test/test_bug1238440.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test - bug 1238440</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <input type="file" id="file" />
+ <script type="application/javascript">
+
+var script;
+
+function step_createScript() {
+ info("Creating script...");
+ var url = SimpleTest.getTestFileURL("script_bug1238440.js");
+ script = SpecialPowers.loadChromeScript(url);
+ next();
+}
+
+function step_destroyScript() {
+ info("Destroying script...");
+ script.destroy();
+ next();
+}
+
+
+function step_createFile() {
+ info("Creating file...");
+
+ function onOpened(message) {
+ var fileList = document.getElementById('file');
+ SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
+ ok(!!message.file, "File created and set");
+ next();
+ }
+
+ script.addMessageListener("file.opened", onOpened);
+ script.sendAsyncMessage("file.open");
+}
+
+function step_changeFile() {
+ info("Changing file...");
+ script.addMessageListener("file.changed", next);
+ script.sendAsyncMessage("file.change");
+}
+
+function step_fileReader(status) {
+ var fr = new FileReader();
+ fr.onload = function() {
+ is(status, true, "onload called!");
+ next();
+ }
+
+ fr.onerror = function(e) {
+ e.preventDefault();
+ is(status, false, "onerror called!");
+ next();
+ }
+
+ fr.readAsArrayBuffer(document.getElementById("file").files[0]);
+}
+
+var steps = [
+ step_createScript,
+ step_createFile,
+ function() { step_fileReader(true); },
+ step_changeFile,
+ function() { step_fileReader(false); },
+ step_destroyScript,
+];
+
+function next() {
+ if (!steps.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var step = steps.shift();
+ step();
+}
+
+SimpleTest.waitForExplicitFinish();
+next();
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1250148.html b/dom/base/test/test_bug1250148.html
new file mode 100644
index 0000000000..b32124ded6
--- /dev/null
+++ b/dom/base/test/test_bug1250148.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1250148
+ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1250148 - FormData and HTML submission compatibility</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <body>
+ <form id="form" enctype="multipart/form-data"><input type="file" name="test" /></form>
+ <script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var f = document.getElementById('form');
+var fd = new FormData(f);
+var get = fd.get("test");
+ok(get instanceof File, "We want a File object.");
+is(get.name, "", "We want a File with an empty name.");
+is(
+ get.type,
+ "application/octet-stream",
+ "We want a File with type application/octet-stream."
+);
+is(get.size, 0, "We want a File with an empty body.");
+
+var getAll = fd.getAll("test");
+ok(Array.isArray(getAll), "We want an array with 1 empty File.");
+is(getAll.length, 1, "We want an array with 1 empty File.");
+is(
+ getAll[0],
+ get,
+ "We want the File returned from getAll to be that returned from get."
+);
+
+var xhr = new XMLHttpRequest();
+xhr.open("POST", "file_bug1250148.sjs", true);
+xhr.onload = function() {
+ var obj = JSON.parse(xhr.responseText);
+
+ ok(Array.isArray(obj), "XHR response is an array.");
+ is(obj.length, 1, "XHR response array contains 1 result.");
+
+ ok("headers" in obj[0], "XHR response has an header value");
+
+ ok("Content-Disposition" in obj[0].headers, "XHR response.headers array has a Content-Desposition value");
+ is(obj[0].headers["Content-Disposition"], "form-data; name=\"test\"; filename=\"\"", "Correct Content-Disposition");
+
+ ok("Content-Type" in obj[0].headers, "XHR response.headers array has a Content-Type value");
+ is(obj[0].headers["Content-Type"], "application/octet-stream", "Correct Content-Type");
+
+ ok("body" in obj[0], "XHR response has a body value");
+ is(obj[0].body, "", "Correct body value");
+
+ SimpleTest.finish();
+}
+xhr.send(fd);
+
+ </script>
+ </body>
+</html>
diff --git a/dom/base/test/test_bug1259588.html b/dom/base/test/test_bug1259588.html
new file mode 100644
index 0000000000..40a272f905
--- /dev/null
+++ b/dom/base/test/test_bug1259588.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for Bug 1259588</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws(new TypeError, function() {
+ new File("");
+ }, "new File(\"\") should throw TypeError exception");
+}, "Test new File(\"\") should throw exception");
+</script>
diff --git a/dom/base/test/test_bug1268962.html b/dom/base/test/test_bug1268962.html
new file mode 100644
index 0000000000..54f99f8456
--- /dev/null
+++ b/dom/base/test/test_bug1268962.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1268962
+-->
+<head>
+ <title>Test for Bug 1268962</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=1268962">Mozilla Bug 1268962</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1268962 **/
+
+function testPrefetchEvent(url, crossorigin, expectLoad) {
+ return new Promise((resolve) => {
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "prefetch");
+ link.setAttribute("href", url);
+ if (crossorigin) {
+ link.setAttribute("crossorigin", "");
+ }
+
+ link.addEventListener("load", () => {
+ ok(expectLoad, "not expecting load event for " + url);
+ link.remove();
+ resolve();
+ });
+ link.addEventListener("error", () => {
+ ok(!expectLoad, "not expecting error event for " + url);
+ link.remove();
+ resolve();
+ });
+ document.head.appendChild(link);
+ });
+}
+
+function testCancelPrefetchNotCrash(url) {
+ var ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"].
+ getService(SpecialPowers.Ci.nsIIOService);
+ var prefetch = SpecialPowers.Cc["@mozilla.org/prefetch-service;1"].
+ getService(SpecialPowers.Ci.nsIPrefetchService);
+
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "prefetch");
+ link.setAttribute("href", url);
+ document.head.appendChild(link);
+
+ // Not actually verifying any value, just to ensure cancelPrefetchPreload
+ // won't cause crash.
+ prefetch.cancelPrefetchPreloadURI(ios.newURI(url), link);
+}
+
+const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs");
+const SAME_ORIGIN = "http://mochi.test:8888" + SJS_PATH;
+const CROSS_ORIGIN = "http://example.com" + SJS_PATH;
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [["network.prefetch-next.aggressive", true]]})
+
+// test same origin
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, false))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, false))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, false))
+
+// test cross origin without CORS
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", false, true))
+
+// test cross origin by redirection without CORS
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=200&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=404&cacheControl=no-cache", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=200&cacheControl=max-age%3D120", false, true))
+.then(() => testPrefetchEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=404&cacheControl=max-age%3D120", false, true))
+
+// test cross origin with CORS request but no CORS response
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120", true, true))
+
+// test cross origin with CORS request and CORS response
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=no-cache&allowOrigin=*", true, false))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=no-cache&allowOrigin=*", true, false))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120&allowOrigin=*", true, true))
+.then(() => testPrefetchEvent(CROSS_ORIGIN + "?statusCode=404&cacheControl=max-age%3D120&allowOrigin=*", true, false))
+
+// test the crash issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1294159
+.then(() => testCancelPrefetchNotCrash(SAME_ORIGIN + "?statusCode=200&cacheControl=max-age%3D120"))
+
+.catch((err) => ok(false, "promise rejected: " + err))
+.then(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1274806.html b/dom/base/test/test_bug1274806.html
new file mode 100644
index 0000000000..c8ccb0bc65
--- /dev/null
+++ b/dom/base/test/test_bug1274806.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1274806
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1274806</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+
+ /** Test for Bug 1274806 **/
+ function test() {
+ window.testWindow = window.open("file_bug1274806.html", "", "");
+ };
+
+ </script>
+</head>
+<body onload="setTimeout(test, 0);">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1274806">Mozilla Bug 1274806</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1281963.html b/dom/base/test/test_bug1281963.html
new file mode 100644
index 0000000000..b2d48cc7ec
--- /dev/null
+++ b/dom/base/test/test_bug1281963.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/1281963
+-->
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>Test for Bug 1281963</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"></div>
+
+<script class="testbody" type="application/javascript">
+
+let pushPref = function(key, value) {
+ return SpecialPowers.pushPrefEnv({"set": [[key, value]]});
+};
+
+let popPref = function() {
+ SpecialPowers.popPrefEnv();
+};
+
+// Run a test to see that we don't hide the hard-coded mimeTypes
+// or plugins when "privacy.resistFingerprinting" is active.
+// See bug 1756280.
+add_task(async function() {
+ for (let rfpEnabled of [true, false]) {
+ await pushPref("privacy.resistFingerprinting", rfpEnabled);
+ for (let pdfDisabled of [true, false]) {
+ await pushPref("pdfjs.disabled", pdfDisabled);
+ if (pdfDisabled && !rfpEnabled) {
+ is(navigator.mimeTypes.length, 0, "navigator.mimeTypes.length should be 0");
+ is(navigator.plugins.length, 0, "navigator.plugins.length should 0");
+ } else {
+ let exampleMimeType = navigator.mimeTypes[0];
+ let examplePlugin = navigator.plugins[0];
+
+ isnot(navigator.mimeTypes[exampleMimeType.type], undefined, "Should reveal mime type");
+ is(navigator.mimeTypes.length, 2, "navigator.mimeTypes.length should be 2");
+
+ isnot(navigator.plugins[examplePlugin.name], undefined, "Should reveal plugin");
+ is(navigator.plugins.length, 5, "navigator.plugins.length should be nonzero");
+ }
+ await popPref();
+ }
+ await popPref();
+ }
+});
+
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug1295852.html b/dom/base/test/test_bug1295852.html
new file mode 100644
index 0000000000..e8049f30a8
--- /dev/null
+++ b/dom/base/test/test_bug1295852.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Bug 1295852</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<body>
+<script>
+
+var names = [
+ "span", "_moz_generated_content_before", "_moz_generated_content_after"
+];
+
+if (SpecialPowers.getBoolPref("dom.animations-api.getAnimations.enabled")) {
+ names.forEach(name => {
+ var element = document.createElement(name);
+ element.animate({ "color": ["red", "blue"] }, { duration: 1000 });
+ is(element.getAnimations().length, 1);
+ });
+} else {
+ ok("Test requires Web Animations, which is disabled.");
+}
+
+</script>
diff --git a/dom/base/test/test_bug1307730.html b/dom/base/test/test_bug1307730.html
new file mode 100644
index 0000000000..e0cad741f9
--- /dev/null
+++ b/dom/base/test/test_bug1307730.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1307730
+-->
+<head>
+ <title>Test for Bug 1307730</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=1307730">Mozilla Bug 1307730</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+const Cu = SpecialPowers.Cu;
+
+function runTest() {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "https://example.com", false);
+ try {
+ xhr.send();
+ } catch (e) {
+ return e.name;
+ }
+ return 'XHR succeeded';
+}
+
+function evalInSandbox(sandbox, func) {
+ return SpecialPowers.unwrap(Cu.evalInSandbox(`(${func.toString()})()`, sandbox));
+}
+
+let sandbox = Cu.Sandbox([window, "https://example.org"],
+ {wantGlobalProperties: ['XMLHttpRequest']});
+is(evalInSandbox(sandbox, runTest), 'NetworkError',
+ "Shouldn't be able to make a CORS request with an expanded principal");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1308069.html b/dom/base/test/test_bug1308069.html
new file mode 100644
index 0000000000..2775ff1b7e
--- /dev/null
+++ b/dom/base/test/test_bug1308069.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1308069
+-->
+<head>
+<title>Bug 1308069</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=1308069">Mozilla Bug 1308069</a>
+<script class="testbody" type="text/javascript">
+
+function testClearPendingErrorEvent() {
+ return new Promise(function(aResolve, aReject) {
+ var hasErrorEvent = false;
+ var imgTarget = new Image();
+
+ var imgForChangingTargetSrc = new Image();
+ // Queue an error event for changing imgTarget's src.
+ imgForChangingTargetSrc.src = '';
+ imgForChangingTargetSrc.onerror = function() {
+ // This clears imgTarget's pending error event.
+ imgTarget.src = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96"><path d="M10,10L32,90L90,32z" fill="lightgreen"/></svg>';
+
+ // Queue an error event for checking and resolving promise.
+ var imgForCheckingAndResolvingPromise = new Image();
+ imgForCheckingAndResolvingPromise.src = '';
+ imgForCheckingAndResolvingPromise.onerror = function() {
+ ok(!hasErrorEvent,
+ 'Should not receive an error event since the pending error event ' +
+ 'should be cleared before it fired');
+ aResolve();
+ };
+ };
+
+ // Setting src to empty string queues an error event.
+ imgTarget.src = '';
+ imgTarget.onerror = function() {
+ hasErrorEvent = true;
+ };
+ });
+}
+
+function testReplacePendingErrorEvent() {
+ return new Promise(function(aResolve) {
+ var numOfErrorEvent = 0;
+ var imgTarget = new Image();
+
+ var imgForChangingTargetSrc = new Image();
+ // Queue an error event for changing imgTarget's src.
+ imgForChangingTargetSrc.src = '';
+ imgForChangingTargetSrc.onerror = function() {
+ // This clears pending error event and fires a new one.
+ imgTarget.src = '';
+
+ // Queue an error event for checking and resolving promise.
+ var imgForCheckingAndResolvingPromise = new Image();
+ imgForCheckingAndResolvingPromise.src = '';
+ imgForCheckingAndResolvingPromise.onerror = function() {
+ is(numOfErrorEvent, 1,
+ 'Should only receive one error event since the first pending error ' +
+ 'event should be cleared before it fired');
+ aResolve();
+ };
+ };
+
+ // Setting src to empty string queues an error event.
+ imgTarget.src = '';
+ imgTarget.onerror = function() {
+ numOfErrorEvent++;
+ };
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+
+Promise.resolve()
+.then(() => testClearPendingErrorEvent())
+.then(() => testReplacePendingErrorEvent())
+.catch((err) => ok(false, "promise rejected: " + err))
+.then(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1314032.html b/dom/base/test/test_bug1314032.html
new file mode 100644
index 0000000000..693eba2f62
--- /dev/null
+++ b/dom/base/test/test_bug1314032.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1314032</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=1314032">Mozilla Bug 1243846</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+ let win = window.open(URL.createObjectURL(new Blob([
+ '<meta charset="utf-8">' +
+ '<script>' +
+ 'let observer = new IntersectionObserver(([entry]) => {' +
+ 'document.body.textContent += entry.time' +
+ '});' +
+ 'observer.observe(document.documentElement);' +
+ '<\/script>'
+ ], {'type': 'text/html'})));
+
+ win.onload = function () {
+ win.close();
+ ok(true);
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div id="log">
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1318303.html b/dom/base/test/test_bug1318303.html
new file mode 100644
index 0000000000..86053b2d7e
--- /dev/null
+++ b/dom/base/test/test_bug1318303.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1318303
+ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1318303</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script>
+ var _createIterator = function (root) {
+ return document.createNodeIterator.call(root.ownerDocument || root,
+ root,
+ NodeFilter.SHOW_ELEMENT
+ | NodeFilter.SHOW_COMMENT
+ | NodeFilter.SHOW_TEXT,
+ function () {
+ return NodeFilter.FILTER_ACCEPT;
+ },
+ false
+ );
+ };
+
+ evil = "<body><object data=''><p></p></object></body>";
+ doc = new DOMParser().parseFromString(evil, 'text/html');
+ body = doc.getElementsByTagName("body")[0];
+ nodeIterator = _createIterator(body);
+ try {
+ while ((currentNode = nodeIterator.nextNode())) {
+ currentNode.removeAttribute("data");
+ }
+ ok(true, "Removing data attributes did not throw error");
+ } catch(err) {
+ ok(false, "Removing data attribute threw error!");
+ }
+ obj = doc.getElementsByTagName("object")[0];
+ const objLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+
+ obj instanceof objLC;
+ obj = SpecialPowers.wrap(obj);
+
+ ok(obj.displayedType == objLC.TYPE_NULL,
+ "object with no given MIME type should be NULL type");
+
+ </script>
+ </head>
+</html>
+
diff --git a/dom/base/test/test_bug1375050.html b/dom/base/test/test_bug1375050.html
new file mode 100644
index 0000000000..5f598d7469
--- /dev/null
+++ b/dom/base/test/test_bug1375050.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1375050
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1375050</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ try { o1 = document.createElement('input'); } catch(e) { console.log(e); };
+ try { o2 = document.createElement('col'); } catch(e) { console.log(e); };
+ try { o4 = document.createRange(); } catch(e) { console.log(e); };
+ try { document.documentElement.appendChild(o1); } catch(e) { console.log(e); };
+ try { for (let p in o1) { let x = o1[p] }; } catch(e) { console.log(e); };
+ try { o4.selectNode(o1); } catch(e) { console.log(e); };
+ try { o6 = document.createComment(" x"); } catch(e) { console.log(e); }
+ try { o4.surroundContents(o6); } catch(e) { console.log(e); }
+ try { o7 = document.implementation.createDocument('', '', null).adoptNode(o1); } catch(e) { console.log(e);};
+ try { o2.appendChild(o1); } catch(e) { console.log(e); };
+ ok(true, "Didn't crash.");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1375050">Mozilla Bug 1375050</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1381710.html b/dom/base/test/test_bug1381710.html
new file mode 100644
index 0000000000..97531d1426
--- /dev/null
+++ b/dom/base/test/test_bug1381710.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1381710
+-->
+<head>
+ <title>Test for Mozilla Bug 1381710</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=1381710">Mozilla Bug 1381710</a>
+<div id="content">
+ <div id="nonedit"></div>
+ <div id="edit" contenteditable=true></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+function test(element)
+{
+ let selection = window.getSelection();
+ selection.removeAllRanges();
+ let range = document.createRange();
+
+ element.innerHTML = "<table><tr id=tr><td id=td>A</td><td>B</td><tr></table>";
+ let td = document.getElementById("td");
+ range.selectNode(td);
+ // Don't throw exception
+ selection.addRange(range);
+ is(selection.anchorNode, document.getElementById("tr"),
+ "anchor node should be <TR> element");
+ element.innerHTML = "";
+}
+
+test(document.getElementById("nonedit"));
+test(document.getElementById("edit"));
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1399605.html b/dom/base/test/test_bug1399605.html
new file mode 100644
index 0000000000..a8e0c6453d
--- /dev/null
+++ b/dom/base/test/test_bug1399605.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1399605</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=1399605">Mozilla Bug 1399605</a>
+<p id="display"></p>
+<div id="content">
+ <div id="target"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+ let observer = new IntersectionObserver(function() {
+ ok(true, "we are still observing");
+ SimpleTest.finish();
+ observer.unobserve(document.getElementById('target'));
+ });
+ observer.observe(document.getElementById('target'));
+ observer.unobserve(document.getElementById('content'));
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div id="log">
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1404385.html b/dom/base/test/test_bug1404385.html
new file mode 100644
index 0000000000..828a44918f
--- /dev/null
+++ b/dom/base/test/test_bug1404385.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1404385
+-->
+<head>
+ <title>Test for Bug 1404385</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=1404385">Mozilla Bug 1404385</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1404385 **/
+is(atob("T0s="), "OK", "atob");
+is(atob(" T0s="), "OK", "atob initial space removal");
+is(atob("T0s= "), "OK", "atob final space removal");
+is(atob("T 0s="), "OK", "atob middle space removal");
+is(atob("dGV zdA=="), "test", "atob middle space removal 2");
+is(atob(""), "", "atob empty string");
+is(atob(" "), "", "atob all whitespace");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1406102.html b/dom/base/test/test_bug1406102.html
new file mode 100644
index 0000000000..a561f1e8b6
--- /dev/null
+++ b/dom/base/test/test_bug1406102.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1406102</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style type="text/css">
+ html {
+ height: 100%;
+ }
+ body {
+ height: 2866px;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1406102">Mozilla Bug 1406102</a>
+<p id="display"></p>
+<div id="content">
+ <div id="target"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+ let observer = new IntersectionObserver(function (changes) {
+ ok(changes[0].intersectionRatio >= 0,
+ 'intersectionRatio should be equal to or greater than zero');
+ if (changes[0].intersectionRatio > 0) {
+ SimpleTest.finish();
+ }
+ });
+ observer.observe(document.body);
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div id="log">
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1421568.html b/dom/base/test/test_bug1421568.html
new file mode 100644
index 0000000000..f4864c81c1
--- /dev/null
+++ b/dom/base/test/test_bug1421568.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1421568
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1421568</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 1421568 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function init() {
+ document.getElementById("content").innerHTML =
+ "<iframe src='about:blank' onload='test(this)'></iframe>";
+ }
+
+ function test(iframe) {
+ var d = iframe.contentDocument;
+ d.body.innerHTML = "<div>";
+ var div = d.body.firstChild;
+ var sr = div.attachShadow({mode: "closed"});
+ is(sr.mode, "closed", "Shadow root should be closed.");
+ is(div.shadowRoot, null, "Closed shadow root shouldn't be exposed.");
+ is(div.openOrClosedShadowRoot, undefined,
+ "openOrClosedShadowRoot should be exposed to the privileged scripts only.");
+ ok("openOrClosedShadowRoot" in SpecialPowers.wrap(div),
+ "Should have openOrClosedShadowRoot in privileged wrapper.")
+ is(SpecialPowers.unwrap(SpecialPowers.wrap(div).openOrClosedShadowRoot), sr);
+ SimpleTest.finish();
+ }
+
+ //--></script>
+</head>
+<body onload="init()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1421568">Mozilla Bug 1421568</a>
+<p id="display"></p>
+<div id="content">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1433073.html b/dom/base/test/test_bug1433073.html
new file mode 100644
index 0000000000..7fe91aa287
--- /dev/null
+++ b/dom/base/test/test_bug1433073.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test bug 1433073</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 synthesizeAccelKeyAndClickAt(aElementId) {
+ const element = document.getElementById(aElementId);
+ synthesizeMouseAtCenter(element, { accelKey: true });
+ }
+
+ function synthesizeAccelKeyAndC() {
+ synthesizeKey("C", { accelKey: true });
+ }
+
+ async function runTest() {
+ synthesizeAccelKeyAndClickAt("x");
+ synthesizeAccelKeyAndClickAt("y");
+ synthesizeAccelKeyAndClickAt("u");
+ synthesizeAccelKeyAndClickAt("v");
+
+ {
+ // Assert content contains the table.
+ // TODO: the `<meta>` element is missing; which is a defect in the
+ // test-code, see https://bugzilla.mozilla.org/show_bug.cgi?id=1632183.
+ const expectedString = "\
+<table>\
+<tbody>\
+<tr>\
+<td id=\"x\">x</td>\
+<td id=\"y\">y</td>\
+</tr>\
+<tr>\
+<td id=\"u\">u</td>\
+<td id=\"v\">v</td>\
+</tr>\
+</tbody>\
+</table>";
+
+ const flavor = "text/html";
+ await SimpleTest.promiseClipboardChange(expectedString,
+ synthesizeAccelKeyAndC, flavor);
+ }
+
+ {
+ // The key point of this check is that the string doesn't contain a
+ // `<tr>`. It's possible that `<tbody>` could be removed, but it's
+ // unknown if other applications rely on it being included.
+ const expectedString = "\
+<html>\
+<body onload=\"onLoad()\">\
+<div id=\"content\">\
+<table><tbody></tbody></table></div></body></html>";
+ const flavor = "text/_moz_htmlcontext";
+ await SimpleTest.promiseClipboardChange(expectedString,
+ synthesizeAccelKeyAndC, flavor);
+ }
+
+ SimpleTest.finish();
+ }
+
+ function onLoad() {
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(runTest);
+ }
+ </script>
+</head>
+<body onLoad="onLoad()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1433073">Mozilla Bug 1433073</a>
+<p id="display"></p>
+<div id="content">
+ <table>
+ <tbody>
+ <tr>
+ <td id="x">x</td>
+ <td id="y">y</td>
+ </tr>
+ <tr>
+ <td id="u">u</td>
+ <td id="v">v</td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1472427.html b/dom/base/test/test_bug1472427.html
new file mode 100644
index 0000000000..902b9cd05b
--- /dev/null
+++ b/dom/base/test/test_bug1472427.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1472427
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1472427</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 1472427 **/
+
+ SimpleTest.waitForExplicitFinish();
+ var image100x100 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAnUlEQVR42u3RAQ0AAAQAMLJqqCA1zP4Kz+qe4IwUIgQhQhAiBCFCECJEiBCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQhAhBiBCECEGIEIQIESIEIUIQIgQh3y1XQhXMIlaKKwAAAABJRU5ErkJggg==";
+ var ifr;
+ var doc;
+ var img;
+ var host;
+ var root;
+ var map;
+ var area;
+
+ function initPage() {
+ ifr = document.createElement("iframe");
+ ifr.src = "about:blank";
+ document.body.appendChild(ifr);
+ ifr.onload = initIframe;
+ }
+
+ function initIframe() {
+ ifr.contentWindow.focus();
+ doc = ifr.contentDocument;
+ host = doc.createElement("div");
+ doc.body.appendChild(host);
+ root = host.attachShadow({mode: "open"});
+
+ img = document.createElement("img");
+ img.useMap = "#map"
+ img.src = image100x100;
+ img.onload = runTest;
+ root.appendChild(img);
+
+ map = doc.createElement("map");
+ map.name = "map";
+ root.appendChild(map);
+
+ area = doc.createElement("area");
+ area.shape = "rect";
+ area.href = "#area";
+ area.coords = "0,0,100,100";
+ map.appendChild(area);
+ }
+
+ function runTest() {
+ var gotClick = false;
+ var expectedTarget = area;
+ root.addEventListener("click",
+ function(e) {
+ gotClick = true;
+ is(e.target, expectedTarget,
+ expectedTarget.localName + " element should be the target for the click.");
+ e.preventDefault();
+ });
+ synthesizeMouse(img, 50, 50, {}, ifr.contentWindow);
+ ok(gotClick, "Should have got a click event.");
+
+ gotclick = false;
+ map.name = "wrongNameMap";
+ expectedTarget = img;
+ synthesizeMouse(img, 50, 50, {}, ifr.contentWindow);
+ ok(gotClick, "Should have got a click event.");
+ SimpleTest.finish();
+ }
+
+ </script>
+</head>
+<body onload="initPage()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1472427">Mozilla Bug 1472427</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1499169.html b/dom/base/test/test_bug1499169.html
new file mode 100644
index 0000000000..7d5141797d
--- /dev/null
+++ b/dom/base/test/test_bug1499169.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1499139
+ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1499169</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/SpecialPowers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ function test() {
+ const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+ let obj = document.getElementById("pdftest");
+
+ obj instanceof OBJLC;
+ obj = SpecialPowers.wrap(obj);
+
+ // Make sure we've set our type correctly even though the mime type isn't quite as expected.
+ ok(obj.displayedType == OBJLC.TYPE_DOCUMENT, "expected document type");
+ SimpleTest.finish();
+ }
+ </script>
+ </head>
+ <body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1499169">Mozilla Bug 1499169</a>
+ <object id="pdftest" onload="test()" data="file_pdfjs_test.pdf" type="application/pdf;charset=UTF-8" width="90%" height="600"></object>
+ </body>
+</html>
diff --git a/dom/base/test/test_bug1576154.html b/dom/base/test/test_bug1576154.html
new file mode 100644
index 0000000000..eca8db6275
--- /dev/null
+++ b/dom/base/test/test_bug1576154.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1576154
+-->
+<head>
+ <title>Test for Bug 1576154</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=1576154">Mozilla Bug 1576154</a>
+<p id="display"></p>
+<!-- bug1576154.sjs returns an SVG image with HTTP error code 500. -->
+<img src="bug1576154.sjs">
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 657191 **/
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+ let img = document.querySelector("img");
+ img.src = "green.png";
+ img.onload = function() {
+ // As long as this doesn't crash, this test passes.
+ ok(true, "test passed");
+ SimpleTest.finish();
+ };
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1632975.html b/dom/base/test/test_bug1632975.html
new file mode 100644
index 0000000000..8b54ca47a5
--- /dev/null
+++ b/dom/base/test/test_bug1632975.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1632975
+-->
+<head>
+ <title>Test for Bug 1632975</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>
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function observeTest(mutationsList) {
+ for (let mutation of mutationsList) {
+ for (let node of mutation.addedNodes) {
+ if (node.nodeName.toLowerCase() == "script") {
+ node.setAttribute("type", "text/zpconsent")
+ }
+ }
+ }
+}
+
+const observer = new MutationObserver(observeTest);
+observer.observe(document.body, { childList: true, subtree: true });
+
+let script2Ran = false;
+let script3Ran = false;
+script4Ran = false;
+
+onload = () => {
+ ok(!script2Ran, "script2 should not have run");
+ ok(!script3Ran, "script3 should not have run");
+ ok(!script4Ran, "script4 should not have run");
+ SimpleTest.finish();
+}
+</script>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1632975">Mozilla Bug 1632975</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <script id="script2">
+ script2Ran = true;
+ </script>
+
+ <script id="script3" type="disabled">
+ script3Ran = true;
+ </script>
+
+ <script id="script4" src="data:text/javascript,script4Ran = true;"></script>
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1639328.html b/dom/base/test/test_bug1639328.html
new file mode 100644
index 0000000000..f7d88de5a4
--- /dev/null
+++ b/dom/base/test/test_bug1639328.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>Test for bug 1639328</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<style>
+ /* To ensure that they're all in the viewport when displayed */
+ iframe {
+ width: 10px;
+ height: 10px;
+ }
+</style>
+<iframe id="http" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
+<iframe id="https" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
+<iframe id="same-origin" src="file_bug1639328.html"></iframe>
+<iframe id="display-none-http" style="display: none" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
+<iframe id="display-none-https" style="display: none" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
+<iframe id="display-none-same-origin" style="display: none" src="file_bug1639328.html"></iframe>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function getOneMessage(frame) {
+ info(`querying ${frame.src} (${frame.id})`);
+ let resolve;
+ let promise = new Promise(r => { resolve = r; });
+ window.addEventListener("message", function(e) {
+ info("got " + JSON.stringify(e.data));
+ resolve(e.data);
+ }, { once: true });
+ frame.contentWindow.postMessage("ping", "*");
+ return promise;
+}
+
+async function ticks(n) {
+ for (let i = 0; i < n; ++i) {
+ await new Promise(resolve => requestAnimationFrame(resolve));
+ }
+}
+
+async function checkFrame(frame, shouldThrottle) {
+ let message = null;
+ do {
+ if (message) {
+ await ticks(2);
+ }
+ message = await getOneMessage(frame);
+ } while (message.throttledFrameRequests != shouldThrottle);
+ is(message.throttledFrameRequests, shouldThrottle, frame.id);
+}
+
+onload = async function() {
+ await SimpleTest.promiseFocus(window);
+ await ticks(2);
+ is(SpecialPowers.DOMWindowUtils.effectivelyThrottlesFrameRequests, false, "Should not be throttling main page");
+ for (let frame of document.querySelectorAll("iframe")) {
+ let shouldThrottle = frame.style.display == "none";
+ await checkFrame(frame, shouldThrottle);
+ info("Switching display of " + frame.id);
+ frame.style.display = shouldThrottle ? "" : "none";
+ await checkFrame(frame, !shouldThrottle);
+ info("And switching display back for " + frame.id);
+ frame.style.display = shouldThrottle ? "none" : "";
+ await checkFrame(frame, shouldThrottle);
+ }
+
+ SimpleTest.finish();
+};
+</script>
diff --git a/dom/base/test/test_bug1640766.html b/dom/base/test/test_bug1640766.html
new file mode 100644
index 0000000000..ea77c99e59
--- /dev/null
+++ b/dom/base/test/test_bug1640766.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1640766
+-->
+<head>
+ <title>Test for Bug 1640766</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=1640766">Mozilla Bug 1640766</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1640766 **/
+
+function waitForMessage(aMsg) {
+ return new Promise((aResolve) => {
+ window.addEventListener("message", function handler(e) {
+ if (e.data != aMsg) {
+ return;
+ }
+
+ info(`receive: ${e.data}`);
+ window.removeEventListener("message", handler);
+ aResolve(e.source);
+ });
+ });
+}
+
+async function testSuspend(aWindow) {
+ let timerRan = false;
+ let timer = aWindow.setTimeout(function() {
+ timerRan = true;
+ }, 0);
+
+ return new Promise((aResolve) => {
+ setTimeout(function() {
+ ok(!timerRan, "timer should not run as the window is suspended");
+ clearTimeout(timer);
+ aResolve();
+ }, 0);
+ });
+}
+
+add_task(async function() {
+ let w = window.open("iframe1_bug1640766.html");
+ let inner = await waitForMessage("ready");
+
+ var utils = SpecialPowers.getDOMWindowUtils(w);
+ utils.enterModalState();
+
+ await testSuspend(w);
+ await testSuspend(inner);
+
+ utils.leaveModalState();
+ w.close();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1648887.html b/dom/base/test/test_bug1648887.html
new file mode 100644
index 0000000000..a185086137
--- /dev/null
+++ b/dom/base/test/test_bug1648887.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1648887
+-->
+<head>
+<title>Test for Bug 1648887</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=1648887">Mozilla Bug 1648887</a>
+<p id="display"></p>
+<iframe srcdoc="<a id='a' href='http://w'>"></iframe>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1648887 **/
+add_task(async function test() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.disable_open_during_load", false],
+ ],
+ });
+
+ let iframe = document.querySelector("iframe");
+ iframe.contentDocument.getElementById('a').click();
+ iframe.contentWindow.open(document.createElement('r').outerHTML,'','h').close();
+ ok(true, "Should not crash");
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug166235.html b/dom/base/test/test_bug166235.html
new file mode 100644
index 0000000000..9743d725f6
--- /dev/null
+++ b/dom/base/test/test_bug166235.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=166235
+https://bugzilla.mozilla.org/show_bug.cgi?id=816298
+-->
+<head>
+ <title>Test for Bug 166235</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=166235">Mozilla Bug 166235 and Bug 816298</a>
+<p id="test0">This text should be copied.</p>
+<p id="test1">This text should<span style="user-select: none;"> NOT</span> be copied.</p>
+<p id="test2">This<span style="user-select: none;"><span style="user-select: text"> text should</span> NOT</span> be copied.</p>
+<p id="test3">This text should<span style="user-select: -moz-none;"> NOT</span> be copied.</p>
+<p id="test4">This<span style="user-select: -moz-none;"><span style="user-select: text"> text should</span> NOT</span> be copied.</p>
+<p id="test5">This<span style="user-select: all"> text should</span> be copied.</p>
+<div id="content" style="display: none">
+
+</div>
+<textarea id="input"></textarea>
+<pre id="test">
+<script type="application/javascript">
+ "use strict";
+
+/** Test for Bug 166235 **/
+ var Cc = SpecialPowers.Cc;
+ var Ci = SpecialPowers.Ci;
+
+ var docShell = SpecialPowers.wrap(window).docShell;
+
+ var documentViewer = docShell.contentViewer
+ .QueryInterface(SpecialPowers.Ci.nsIContentViewerEdit);
+
+ var clipboard = Cc["@mozilla.org/widget/clipboard;1"]
+ .getService(SpecialPowers.Ci.nsIClipboard);
+
+ var textarea = SpecialPowers.wrap(document.getElementById('input'));
+
+ function getLoadContext() {
+ return SpecialPowers.wrap(window).docShell
+ .QueryInterface(Ci.nsILoadContext);
+ }
+
+ function copyChildrenToClipboard(id) {
+ textarea.blur();
+ clipboard.emptyClipboard(1);
+ window.getSelection().selectAllChildren(document.getElementById(id));
+ documentViewer.copySelection();
+
+ is(clipboard.hasDataMatchingFlavors(["text/plain"], 1), true);
+ is(clipboard.hasDataMatchingFlavors(["text/html"], 1), true);
+ }
+ function getClipboardData(mime) {
+ var transferable = Cc['@mozilla.org/widget/transferable;1']
+ .createInstance(SpecialPowers.Ci.nsITransferable);
+ transferable.init(getLoadContext());
+ transferable.addDataFlavor(mime);
+ clipboard.getData(transferable, 1);
+ var data = SpecialPowers.createBlankObject();
+ transferable.getTransferData(mime, data) ;
+ return SpecialPowers.wrap(data);
+ }
+ function testHtmlClipboardValue(mime, expected, test) {
+ var expectedValue = expected;
+ // For Windows, navigator.platform returns "Win32".
+ if (navigator.platform.includes("Win")) {
+ expectedValue = kTextHtmlPrefixClipboardDataWindows + expected + kTextHtmlSuffixClipboardDataWindows;
+ }
+ testClipboardValue(mime, expectedValue, test);
+ }
+ function testClipboardValue(mime, expected, test) {
+ var data = getClipboardData(mime);
+ is (data.value == null ? data.value :
+ data.value.QueryInterface(SpecialPowers.Ci.nsISupportsString).data,
+ expected,
+ mime + " value in the clipboard");
+ return data.value;
+ }
+ function testPasteText(expected, test) {
+ textarea.value="";
+ textarea.focus();
+ textarea.editor.paste(1);
+ is(textarea.value, expected, test + ": textarea paste");
+ }
+ function testInnerHTML(id, expected) {
+ var value = document.getElementById(id).innerHTML;
+ is(value, expected, id + ".innerHTML");
+ }
+
+// expected results for Selection.toString()
+var originalStrings = [
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.'
+];
+
+// expected results for clipboard text/html
+var clipboardHTML = [
+ '<p id=\"test0\">This text should be copied.</p>',
+ '<p id=\"test1\">This text should be copied.</p>',
+ '<p id=\"test2\">This<span style=\"user-select: text\"> text should</span> be copied.</p>',
+ '<p id=\"test3\">This text should be copied.</p>',
+ '<p id=\"test4\">This<span style=\"user-select: text\"> text should</span> be copied.</p>',
+ '<p id=\"test5\">This<span style=\"user-select: all\"> text should</span> be copied.</p>',
+];
+
+// expected results for clipboard text/plain
+var clipboardUnicode = [
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.'
+];
+
+// expected results for .innerHTML
+var innerHTMLStrings = [
+ 'This text should be copied.',
+ 'This text should<span style=\"user-select: none;\"> NOT</span> be copied.',
+ 'This<span style=\"user-select: none;\"><span style=\"user-select: text\"> text should</span> NOT</span> be copied.',
+ 'This text should<span style=\"user-select: -moz-none;\"> NOT</span> be copied.',
+ 'This<span style=\"user-select: -moz-none;\"><span style=\"user-select: text\"> text should</span> NOT</span> be copied.',
+ 'This<span style=\"user-select: all\"> text should</span> be copied.',
+];
+
+// expected results for pasting into a TEXTAREA
+var textareaStrings = [
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.',
+ 'This text should be copied.'
+];
+
+for (var i = 0; i < originalStrings.length; i++) {
+ var id = 'test' + i;
+ copyChildrenToClipboard(id);
+ is(window.getSelection().toString(), originalStrings[i], id + ' Selection.toString()');
+ testHtmlClipboardValue("text/html", clipboardHTML[i], id);
+ testClipboardValue("text/plain", clipboardUnicode[i], id);
+ testInnerHTML(id, innerHTMLStrings[i]);
+ testPasteText(textareaStrings[i], id + '.innerHTML');
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1667316.html b/dom/base/test/test_bug1667316.html
new file mode 100644
index 0000000000..2770d58dd4
--- /dev/null
+++ b/dom/base/test/test_bug1667316.html
@@ -0,0 +1,153 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1667316
+-->
+<head>
+ <title>Test for Bug 1667316</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=1667316">Mozilla Bug 1667316</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1667316 **/
+
+function testPreloadEvent(url, crossorigin, expectLoad) {
+ return new Promise((resolve) => {
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "preload");
+ link.setAttribute("href", url);
+ link.setAttribute("as", "fetch");
+ if (crossorigin) {
+ link.setAttribute("crossorigin", "");
+ }
+
+ link.addEventListener("load", () => {
+ ok(expectLoad, "not expecting load event for " + url);
+ link.remove();
+ resolve();
+ });
+ link.addEventListener("error", () => {
+ ok(!expectLoad, "not expecting error event for " + url);
+ link.remove();
+ resolve();
+ });
+ document.head.appendChild(link);
+ });
+}
+
+function testChangePrefetchToPreload(url) {
+ return new Promise((resolve) => {
+ var preloaded = false;
+ var link = document.createElement("LINK");
+ link.setAttribute("rel", "prefetch");
+ link.setAttribute("href", url);
+ link.setAttribute("as", "fetch");
+
+ link.addEventListener("load", () => {
+ ok(preloaded, "this will happen only on a preload");
+ ok(true, "not expecting load event for " + url);
+ link.remove();
+ resolve();
+ });
+ link.addEventListener("error", () => {
+ ok(false, "not expecting error event for " + url);
+ link.remove();
+ resolve();
+ });
+ document.head.appendChild(link);
+ preloaded = true;
+ link.setAttribute("rel", "preload");
+ })
+};
+
+const SJS_PATH = window.location.pathname.replace(/[^/]+$/, "file_bug1268962.sjs");
+// eslint-disable-next-line @microsoft/sdl/no-insecure-url
+const SAME_ORIGIN = "http://mochi.test:8888" + SJS_PATH;
+// eslint-disable-next-line @microsoft/sdl/no-insecure-url
+const CROSS_ORIGIN = "http://example.com" + SJS_PATH;
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [["network.preload", true]]})
+
+
+.then(async () => {
+ await SpecialPowers.spawnChrome([], () => {
+
+let window = this.browsingContext.currentWindowGlobal;
+window.ChannelEventSink = {
+ _classDescription: "WebRequest channel event sink",
+ _classID: Components.ID("115062f8-92f1-11e5-8b7f-08001110f7ec"),
+ _contractID: "@mozilla.org/webrequest/channel-event-sink;1",
+
+ QueryInterface: ChromeUtils.generateQI(["nsIChannelEventSink", "nsIFactory"]),
+
+ init() {
+ Components.manager
+ .QueryInterface(Ci.nsIComponentRegistrar)
+ .registerFactory(
+ this._classID,
+ this._classDescription,
+ this._contractID,
+ this
+ );
+ },
+
+ register() {
+ Services.catMan.addCategoryEntry(
+ "net-channel-event-sinks",
+ this._contractID,
+ this._contractID,
+ false,
+ true
+ );
+ },
+
+ unregister() {
+ Components.manager
+ .QueryInterface(Ci.nsIComponentRegistrar)
+ .unregisterFactory(this._classID, window.ChannelEventSink);
+ Services.catMan.deleteCategoryEntry(
+ "net-channel-event-sinks",
+ this._contractID,
+ false
+ );
+ },
+
+ // nsIChannelEventSink implementation
+ asyncOnChannelRedirect(oldChannel, newChannel, flags, redirectCallback) {
+ // Abort the redirection.
+ redirectCallback.onRedirectVerifyCallback(Cr.NS_ERROR_NO_INTERFACE);
+ },
+
+ // nsIFactory implementation
+ createInstance(iid) {
+ return this.QueryInterface(iid);
+ },
+};
+
+window.ChannelEventSink.init();
+window.ChannelEventSink.register();
+})})
+
+// test cross origin by redirection without CORS
+.then(() => testPreloadEvent(SAME_ORIGIN + "?redirect=crossorigin&statusCode=200&cacheControl=no-cache", false, false))
+
+.catch((err) => ok(false, "promise rejected: " + err))
+.then(async () => {
+ await SpecialPowers.spawnChrome([], () => {
+ let window = this.browsingContext.currentWindowGlobal;
+ window.ChannelEventSink.unregister();
+ delete window.ChannelEventSink;
+ })
+})
+.then(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1730284.html b/dom/base/test/test_bug1730284.html
new file mode 100644
index 0000000000..6a24f69b05
--- /dev/null
+++ b/dom/base/test/test_bug1730284.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>Test for bug 1730284 (throttling of same-origin iframes)</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<style>
+ iframe {
+ width: 10px;
+ height: 10px;
+ }
+ .display-none {
+ display: none;
+ }
+ .vis-hidden {
+ visibility: hidden
+ }
+ .transparent {
+ opacity: 0;
+ }
+ .zero-size {
+ width: 0;
+ height: 0;
+ border: 0;
+ }
+ .offscreen {
+ position: absolute;
+ top: 500%;
+ }
+ .scroller {
+ height: 100px;
+ overflow: auto;
+ }
+ .scroller-padding {
+ height: 500px;
+ }
+</style>
+<iframe class="visible"></iframe>
+<iframe class="display-none" data-throttled-expected></iframe>
+<iframe class="vis-hidden"></iframe>
+<iframe class="transparent"></iframe>
+<iframe class="zero-size"></iframe>
+<div class="scroller">
+ <div class="scroller-padding"></div>
+ <iframe class="scrolled-out-of-view" data-throttled-expected></iframe>
+</div>
+<iframe class="offscreen" data-throttled-expected></iframe>
+<iframe class="offscreen zero-size" data-throttled-expected></iframe>
+<iframe class="offscreen vis-hidden" data-throttled-expected></iframe>
+<iframe class="offscreen transparent" data-throttled-expected></iframe>
+<script>
+async function assertThrottled(win, shouldThrottle, msg) {
+ if (isXOrigin) {
+ // In XOrigin mode we need to depend as well on the main process having
+ // painted the cross-origin iframe at least once for coordinates to be
+ // correct.
+ await SimpleTest.promiseWaitForCondition(() => {
+ return SpecialPowers.getDOMWindowUtils(win).effectivelyThrottlesFrameRequests == shouldThrottle;
+ }, msg);
+ }
+ is(SpecialPowers.getDOMWindowUtils(win).effectivelyThrottlesFrameRequests, shouldThrottle, msg);
+}
+
+add_task(async function() {
+ await SimpleTest.promiseFocus(window);
+ await assertThrottled(window, false, "Should not be throttling main page");
+ for (let frame of document.querySelectorAll("iframe")) {
+ let shouldThrottle = frame.getAttribute("data-throttled-expected") !== null;
+ await assertThrottled(frame.contentWindow, shouldThrottle, frame.className);
+ }
+});
+</script>
diff --git a/dom/base/test/test_bug1739957.html b/dom/base/test/test_bug1739957.html
new file mode 100644
index 0000000000..fdfe1e3861
--- /dev/null
+++ b/dom/base/test/test_bug1739957.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Importing a node should respect sandbox</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ function imageHasLoaded() {
+ return fetch("bug1739957.sjs?loaded")
+ .then(response => response.text())
+ .then(loaded => Boolean(loaded));
+ }
+
+ async function test() {
+ let newDiv = document.createElement("div");
+ newDiv.innerHTML = `<img src="bug1739957.sjs" onload="parent.postMessage('handlerRuns', '*')">`;
+
+ let eventHandlerCalled = false;
+ window.addEventListener("message", () => { eventHandlerCalled = true; }, { once: true })
+
+ document.getElementById("frame").contentDocument.body.appendChild(newDiv);
+
+ await SimpleTest.promiseWaitForCondition(imageHasLoaded, "Wait for image to load");
+
+ ok(!eventHandlerCalled, "Event handlers on imported nodes shouldn't execute if sandbox doesn't allow script");
+
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body onload="test();">
+<p id="display"></p>
+<iframe id="frame" sandbox="allow-same-origin" src="about:blank"></iframe>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug1784187.html b/dom/base/test/test_bug1784187.html
new file mode 100644
index 0000000000..6f9f782e3e
--- /dev/null
+++ b/dom/base/test/test_bug1784187.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1784187
+-->
+<head>
+ <title>Test for Bug 1784187</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>
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function observeTest(mutationsList) {
+ for (let mutation of mutationsList) {
+ for (let n of mutation.addedNodes) {
+ if (n.id === 'content') {
+ is(n.innerHTML.trim(), "<script><\/script>", "Comment should not have been observed.");
+ SimpleTest.finish();
+ }
+ }
+ }
+}
+
+var observer = new MutationObserver(observeTest);
+observer.observe(document.body, { childList: true, subtree: true });
+</script>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1784187">Mozilla Bug 1784187</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <script></script>
+ <!-- Test comment that shouldn't be observed -->
+</div>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug1799354.html b/dom/base/test/test_bug1799354.html
new file mode 100644
index 0000000000..ba2177d576
--- /dev/null
+++ b/dom/base/test/test_bug1799354.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test bug 1799354</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ add_task(t => {
+ let root = document.createElement("div");
+ root.innerHTML = "<div id='a'>text<div id='b'>text2</div></div>";
+ const a = root.firstChild;
+ const b = a.lastChild;
+ const txt = b.previousSibling;
+ const txt2 = b.firstChild;
+ let events = [];
+ function listener(event) {
+ events.push(event);
+ }
+ root.addEventListener("DOMNodeRemoved", listener);
+
+ // Test 1, replace current children with an element.
+ b.replaceChildren(txt);
+ is(events.length, 2, "Should have got two DOMNodeRemoved events");
+ // replaceChildren removes first all the child nodes of b and then when
+ // a new child is added to it, that child is removed from its original parent.
+ // https://dom.spec.whatwg.org/commit-snapshots/6b3f055f3891a63423bf235d46f38ffdb298c2e7/#concept-node-replace-all
+ is(events[0].target, txt2);
+ is(events[0].relatedNode, b);
+ is(events[1].target, txt);
+ is(events[1].relatedNode, a);
+
+ // Test 2, replace current children with a document fragment.
+ events = [];
+ const df = document.createDocumentFragment();
+ const dfChild1 = document.createElement("div");
+ df.appendChild(dfChild1);
+ const dfChild2 = document.createElement("div");
+ df.appendChild(dfChild2);
+ df.addEventListener("DOMNodeRemoved", listener);
+
+ b.replaceChildren(df);
+ is(events.length, 3, "Should have got three DOMNodeRemoved events");
+ is(events[0].target, txt);
+ is(events[0].relatedNode, b);
+ is(events[1].target, dfChild1);
+ is(events[1].relatedNode, df);
+ is(events[2].target, dfChild2);
+ is(events[2].relatedNode, df);
+
+ // Test 3, replace current children with multiple elements.
+ events = [];
+ const rootChild1 = document.createElement("div");
+ root.appendChild(rootChild1);
+ const rootChild2 = document.createElement("div");
+ root.appendChild(rootChild2);
+ // Note, if replaceChildren gets more than one parameter, it moves the nodes
+ // to a new internal document fragment and then removes the current children.
+ b.replaceChildren(rootChild1, rootChild2);
+ is(events.length, 4, "Should have got four DOMNodeRemoved events");
+ is(events[0].target, rootChild1);
+ is(events[0].relatedNode, root);
+ is(events[1].target, rootChild2);
+ is(events[1].relatedNode, root);
+ is(events[2].target, dfChild1);
+ is(events[2].relatedNode, b);
+ is(events[3].target, dfChild2);
+ is(events[3].relatedNode, b);
+ });
+ </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug199959.html b/dom/base/test/test_bug199959.html
new file mode 100644
index 0000000000..e807646c10
--- /dev/null
+++ b/dom/base/test/test_bug199959.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=199959
+-->
+<head>
+ <title>Test for Bug 199959</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=199959">Mozilla Bug 199959</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="attrTest" testAttr="testValue"></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 199959 **/
+
+// From ACID3
+var attrTest = document.getElementById("attrTest");
+var attr = attrTest.getAttributeNode("testAttr");
+ok(attr.specified, "Attribute isn't specified!");
+attrTest.removeAttributeNode(attr);
+ok(attr.specified, "Attribute isn't specified after removal!");
+
+// From bug 199959
+attr = document.createAttribute('foo');
+ok(attr.specified, "Attribute isn't specified!");
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug218236.html b/dom/base/test/test_bug218236.html
new file mode 100644
index 0000000000..d691ad4418
--- /dev/null
+++ b/dom/base/test/test_bug218236.html
@@ -0,0 +1,139 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=218236
+-->
+<head>
+ <title>Test for Bug 218236</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=218236">Mozilla Bug 218236</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 218236 **/
+
+SimpleTest.waitForExplicitFinish();
+
+/* Test data */
+
+var url_200 = window.location.href;
+var url_404 = url_200.replace(/[^/]+$/, "this_file_is_not_going_to_be_there.dummy");
+var url_connection_error = url_200.replace(/^(\w+:\/\/[^/]+?)(:\d+)?\//, "$1:9546/");
+
+// List of tests: name of the test, URL to be requested, expected sequence
+// of events and optionally a function to be called from readystatechange handler.
+// Numbers in the list of events are values of XMLHttpRequest.readyState
+// when readystatechange event is triggered.
+var tests = [
+ ["200 OK", url_200, [1, 2, 3, 4, "load"], null],
+ ["404 Not Found", url_404, [1, 2, 3, 4, "load"], null],
+ ["connection error", url_connection_error, [1, 4, "error"], null],
+ ["abort() call on readyState = 1", url_200, [1, 4], null, doAbort1],
+ ["abort() call on readyState = 2", url_200, [1, 2, 4], doAbort2],
+];
+
+var testName = null;
+var currentState = 0;
+var currentSequence = null;
+var expectedSequence = null;
+var currentCallback = null;
+var finalizeTimeoutID = null;
+
+var request = null;
+
+runNextTest();
+
+function doAbort1() {
+ if (request.readyState == 1)
+ request.abort();
+}
+function doAbort2() {
+ if (request.readyState == 2)
+ request.abort();
+}
+
+/* Utility functions */
+
+function runNextTest() {
+ if (tests.length) {
+ var test = tests.shift();
+
+ // Initialize state variables
+ testName = test[0]
+ currentState = 0;
+ currentSequence = [];
+ expectedSequence = test[2];
+ currentCallback = test[3];
+ postSendCallback = test[4];
+
+ // Prepare request object
+ request = new XMLHttpRequest();
+ request.onreadystatechange = onReadyStateChange;
+ request.open("GET", test[1]);
+ request.onload = onLoad;
+ request.onerror = onError;
+
+ // Start request
+ request.send(null);
+ if (postSendCallback)
+ postSendCallback();
+ }
+ else
+ SimpleTest.finish();
+}
+
+function finalizeTest() {
+ finalizeTimeoutID = null;
+ ok(compareArrays(expectedSequence, currentSequence), "event sequence for '" + testName + "' was " + currentSequence.join(", "));
+
+ runNextTest();
+}
+
+function onReadyStateChange() {
+ clearTimeout(finalizeTimeoutID);
+ finalizeTimeoutID = null;
+
+ currentState = request.readyState;
+ currentSequence.push(currentState);
+
+ if (currentState == 4) {
+ // Allow remaining event to fire but then we are finished with this test
+ // unless we get another onReadyStateChange in which case we'll cancel
+ // this timeout
+ finalizeTimeoutID = setTimeout(finalizeTest, 0);
+ }
+
+ if (currentCallback)
+ currentCallback();
+}
+
+function onLoad() {
+ currentSequence.push("load");
+}
+
+function onError() {
+ currentSequence.push("error");
+}
+
+function compareArrays(array1, array2) {
+ if (array1.length != array2.length)
+ return false;
+
+ for (var i = 0; i < array1.length; i++)
+ if (array1[i] != array2[i])
+ return false;
+
+ return true;
+}
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug218277.html b/dom/base/test/test_bug218277.html
new file mode 100644
index 0000000000..bcad1dafd7
--- /dev/null
+++ b/dom/base/test/test_bug218277.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=218277
+-->
+<head>
+ <title>Test for Bug 218277</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=218277">Mozilla Bug 218277</a>
+<p id="display"></p>
+<div id="content" style="display: block">
+ <input id="ctrl" name="ctrl" size="20" value="keep&nbsp;together" readonly />
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 218277 **/
+
+is(escape($('ctrl').value), "keep%A0together", "nbsp preserved in form submissions");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug238409.html b/dom/base/test/test_bug238409.html
new file mode 100644
index 0000000000..ac0b261548
--- /dev/null
+++ b/dom/base/test/test_bug238409.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=238409
+-->
+<head>
+ <title>Test for Bug 238409</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=238409">Mozilla Bug 238409</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <table id="table_spacing0" cellspacing="0">
+ <tr><td>cellspacing="0"</td></tr>
+ </table>
+
+ <table id="table_spacing2" cellspacing="2">
+ <tr><td>cellspacing="2"</td></tr>
+ </table>
+
+ <table id="table_spacingNone">
+ <tr><td>no cellspacing</td></tr>
+ </table>
+
+ <table id="table_spacingMalformed" cellspacing>
+ <tr><td>malformed cellspacing</td></tr>
+ </table>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 238409 **/
+
+ok(document.getElementById("table_spacing0").cellSpacing == "0", "parsing table with cellspacing='0'");
+ok(document.getElementById("table_spacing2").cellSpacing == "2", "parsing table with cellspacing='2'");
+ok(document.getElementById("table_spacingNone").cellSpacing == "", "parsing table without cellspacing");
+ok(document.getElementById("table_spacingMalformed").cellSpacing == "", "parsing table with malformed cellspacing");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug254337.html b/dom/base/test/test_bug254337.html
new file mode 100644
index 0000000000..1c68b18c14
--- /dev/null
+++ b/dom/base/test/test_bug254337.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=254337
+-->
+<head>
+ <title>Test for Bug 254337</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=254337">Mozilla Bug 254337</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 254337 **/
+
+var el = document.createElement("div");
+el.setAttribute("class", "foobar1");
+is(el.className, "foobar1", "Wrong className!");
+el.className += " foobar2 ";
+is(el.className, "foobar1 foobar2 ", "Appending to className didn't work!");
+el.className += "foobar3";
+is(el.className, "foobar1 foobar2 foobar3", "Appending to className didn't work!");
+
+var el = document.createElement("div");
+el.setAttribute("class", " foobar1 ");
+is(el.className, " foobar1 ", "Wrong className!");
+el.className += "foobar2";
+is(el.className, " foobar1 foobar2", "Appending to className didn't work!");
+el.setAttribute("class", " ");
+is(el.getAttribute("class"), " ", "class attribute didn't store the right value!");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug270145.xhtml b/dom/base/test/test_bug270145.xhtml
new file mode 100644
index 0000000000..ebf89ef5ca
--- /dev/null
+++ b/dom/base/test/test_bug270145.xhtml
@@ -0,0 +1,51 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=270145
+-->
+<head>
+ <title>Test the html copy encoder with XHTML </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=270145">Mozilla Bug 270145</a>
+<p id="display"></p>
+<div id="content" >
+<p id="foo"><![CDATA[a text to copy]]></p>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//<![CDATA[
+function testHtmlCopyEncoder () {
+ var encoder = SpecialPowers.Cu.createHTMLCopyEncoder();
+ var out, expected;
+
+ var node = document.getElementById('draggable');
+
+ var select = window.getSelection();
+ select.removeAllRanges();
+
+ node = document.getElementById("foo").firstChild;
+ var range = document.createRange();
+ range.setStart(node, 0);
+ range.setEnd(node, "a text to copy".length);
+ select.addRange(range);
+ encoder.init(document, "text/html", 0);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = "a text to copy";
+ is(out, expected, "test xhtml copy");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlCopyEncoder);
+//]]>
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug276037-1.html b/dom/base/test/test_bug276037-1.html
new file mode 100644
index 0000000000..2216480337
--- /dev/null
+++ b/dom/base/test/test_bug276037-1.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=276037
+-->
+<head>
+ <title>Test for Bug 276037</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=276037">Mozilla Bug 276037</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 276037 **/
+function countElements (node, namespaceURI, localName) {
+ var count = 0;
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var child = node.childNodes[i];
+ if (child.nodeType == Node.ELEMENT_NODE && child.localName == localName &&
+ child.namespaceURI == namespaceURI) {
+ count++;
+ }
+ if (child.hasChildNodes()) {
+ count += countElements(child, namespaceURI, localName);
+ }
+ }
+ return count;
+}
+
+function checkElements(namespaceURI, localName) {
+ var elementsNS = document.getElementsByTagNameNS(namespaceURI, localName);
+ var elements = document.getElementsByTagName(localName);
+ var elementCount = countElements(document, namespaceURI, localName);
+ const gEBTN = 'document.getElementsByTagName(\'' + localName + '\').length: ' + elements.length;
+ const gEBTNNS = '; document.getElementsByTagNameNS(\'' + namespaceURI + '\', \'' + localName + '\').length: ' + elementsNS.length;
+
+ text1 = gEBTN + '; element count: ' + elementCount;
+ text2 = gEBTNNS + '; element count: ' + elementCount;
+
+ is(elements.length, elementCount, text1);
+ is(elementsNS.length, elementCount, text2);
+ is(global.gEBTN[namespaceURI][localName].length, elementCount, text1);
+ is(global.gEBTNNS[namespaceURI][localName].length, elementCount, text2);
+}
+
+const xhtmlNS = 'http://www.w3.org/1999/xhtml';
+
+function checkSpansAndScripts () {
+ checkElements(xhtmlNS, 'span');
+ checkElements(xhtmlNS, 'script');
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() { checkSpansAndScripts() });
+addLoadEvent(SimpleTest.finish);
+
+// Init our global lists
+var global = {};
+global.gEBTN = {};
+global.gEBTN[xhtmlNS] = {};
+global.gEBTNNS = {};
+global.gEBTNNS[xhtmlNS] = {};
+
+global.gEBTN[xhtmlNS].span = document.getElementsByTagName("span");
+global.gEBTNNS[xhtmlNS].span = document.getElementsByTagNameNS(xhtmlNS, "span");
+global.gEBTN[xhtmlNS].script = document.getElementsByTagName("script");
+global.gEBTNNS[xhtmlNS].script = document.getElementsByTagNameNS(xhtmlNS, "script");
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug276037-2.xhtml b/dom/base/test/test_bug276037-2.xhtml
new file mode 100644
index 0000000000..d0155a4168
--- /dev/null
+++ b/dom/base/test/test_bug276037-2.xhtml
@@ -0,0 +1,106 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=276037
+-->
+<head>
+ <title>Test for Bug 276037</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=276037">Mozilla Bug 276037</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+/** Test for Bug 276037 **/
+function countElements (node, namespaceURI, tagName) {
+ var count = 0;
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var child = node.childNodes[i];
+ if (child.nodeType == Node.ELEMENT_NODE && child.tagName == tagName &&
+ child.namespaceURI == namespaceURI) {
+ count++;
+ }
+ if (child.hasChildNodes()) {
+ count += countElements(child, namespaceURI, tagName);
+ }
+ }
+ return count;
+}
+
+function checkElements(namespaceURI, tagName) {
+ var elementsNS = document.getElementsByTagNameNS(namespaceURI, tagName);
+ var elements = document.getElementsByTagName(tagName);
+ var elementCount = countElements(document, namespaceURI, tagName);
+ const gEBTN = 'document.getElementsByTagName(\'' + tagName + '\').length: ' + elements.length;
+ const gEBTNNS = '; document.getElementsByTagNameNS(\'' + namespaceURI + '\', \'' + tagName + '\').length: ' + elementsNS.length;
+
+ var text1 = gEBTN + '; element count: ' + elementCount;
+ var text2 = gEBTNNS + '; element count: ' + elementCount;
+
+ is(elements.length, elementCount, text1);
+ is(elementsNS.length, elementCount, text2);
+ is(global.gEBTN[namespaceURI][tagName].length, elementCount, text1);
+ is(global.gEBTNNS[namespaceURI][tagName].length, elementCount, text2);
+}
+
+const xhtmlNS = 'http://www.w3.org/1999/xhtml';
+
+function checkSpansAndScripts () {
+ checkElements(xhtmlNS, 'span');
+ checkElements(xhtmlNS, 'script');
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() { checkSpansAndScripts() });
+addLoadEvent(SimpleTest.finish);
+
+// Init our global lists
+var global = {};
+global.gEBTN = {};
+global.gEBTN[xhtmlNS] = {};
+global.gEBTNNS = {};
+global.gEBTNNS[xhtmlNS] = {};
+global.gEBTN[xhtmlNS].span = document.getElementsByTagName("span");
+global.gEBTNNS[xhtmlNS].span = document.getElementsByTagNameNS(xhtmlNS, "span");
+global.gEBTN[xhtmlNS].script = document.getElementsByTagName("script");
+global.gEBTNNS[xhtmlNS].script = document.getElementsByTagNameNS(xhtmlNS, "script");
+]]>
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+<p><span>Static text in span.</span></p>
+<script type="text/javascript">
+checkSpansAndScripts();
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug282547.html b/dom/base/test/test_bug282547.html
new file mode 100644
index 0000000000..4c310a2724
--- /dev/null
+++ b/dom/base/test/test_bug282547.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=282547
+-->
+<head>
+ <title>Test for Bug 282547</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=282547">Mozilla Bug 282547</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<script class="testbody" type="text/javascript">
+
+function xhr_userpass_sync() {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'bug282547.sjs', false, 'username', 'password');
+
+ xhr.send(null);
+ ok(xhr.status == 401, "Status 401");
+
+ runTests();
+}
+
+function xhr_userpass_async() {
+ xhr = new XMLHttpRequest();
+ xhr.open('GET', 'bug282547.sjs', true, 'username', 'password');
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ ok(xhr.status == 401, "Status 401");
+ runTests();
+ }
+ }
+
+ xhr.send(null);
+}
+
+function xhr_auth_header_sync() {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'bug282547.sjs', false);
+ xhr.setRequestHeader("Authorization", "42");
+
+ xhr.send(null);
+ ok(xhr.status == 401, "Status 401");
+
+ runTests();
+}
+
+function xhr_auth_header_async() {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'bug282547.sjs', true);
+ xhr.setRequestHeader("Authorization", "42");
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ ok(xhr.status == 401, "Status 401");
+ runTests();
+ }
+ }
+
+ xhr.send(null);
+}
+
+function xhr_crossorigin_sync() {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://example.com/tests/dom/base/test/bug282547.sjs', true);
+ xhr.withCredentials = true;
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ ok(xhr.status == 401, "Status 401");
+ runTests();
+ }
+ }
+
+ xhr.send(null);
+}
+
+var tests = [ xhr_userpass_sync,
+ xhr_userpass_async,
+ xhr_auth_header_sync,
+ xhr_auth_header_async,
+ /* Disabled: bug799540 xhr_crossorigin_sync */ ];
+function runTests() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+runTests();
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug28293.html b/dom/base/test/test_bug28293.html
new file mode 100644
index 0000000000..332c75e42b
--- /dev/null
+++ b/dom/base/test/test_bug28293.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=28293
+-->
+<head>
+ <title>Test for Bug 28293</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>
+scriptInsertedExternalExecuted = false;
+res = 'A';
+
+SimpleTest.waitForExplicitFinish();
+onload = function () {
+
+ res+='2';
+
+ s = document.createElement('script');
+ s.textContent="res+='g';";
+ s.defer = true;
+ document.body.appendChild(s);
+
+ res+='3';
+
+ s = document.createElement('script');
+ s.textContent="res+='i';done()";
+ s.defer = true;
+ document.body.appendChild(s);
+
+ res+='4';
+}
+
+function done() {
+ is(res, "AacBCDEFGeHIJb1M2g3i", "scripts executed in the wrong order");
+ ok(scriptInsertedExternalExecuted, "Dynamic script did not block load");
+ SimpleTest.finish();
+}
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=28293">Mozilla Bug 28293</a>
+
+<script defer>
+res += 'a';
+</script>
+<script defer src="data:text/plain,res+='b'"></script>
+<script defer>
+res += 'c';
+</script>
+<script>
+res += 'B';
+</script>
+<script>
+res += 'C';
+
+s = document.createElement('script');
+s.textContent="res+='D';";
+document.body.appendChild(s);
+
+res += 'E';
+</script>
+<script>
+res += 'F';
+document.addEventListener("DOMContentLoaded", function() {
+ res += '1'
+ s = document.createElement('script');
+ s.src="file_bug28293.sjs?res+='M';";
+ document.body.appendChild(s);
+});
+res += 'G';
+</script>
+<script defer>
+res += 'e';
+</script>
+<script src="file_bug28293.sjs?res+='H';"></script>
+<script>
+res += 'I';
+s = document.createElement('script');
+s.src="file_bug28293.sjs?scriptInsertedExternalExecuted=true;";
+document.body.appendChild(s);
+res += 'J';
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug28293.xhtml b/dom/base/test/test_bug28293.xhtml
new file mode 100644
index 0000000000..47d73a01b4
--- /dev/null
+++ b/dom/base/test/test_bug28293.xhtml
@@ -0,0 +1,87 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=28293
+-->
+<head>
+ <title>Test for Bug 28293</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>
+scriptInsertedExternalExecuted = false;
+res = 'A';
+
+SimpleTest.waitForExplicitFinish();
+onload = function () {
+
+ res+='2';
+
+ s = document.createElement('script');
+ s.textContent="res+='g';";
+ s.defer = true;
+ document.body.appendChild(s);
+
+ res+='3';
+
+ s = document.createElement('script');
+ s.textContent="res+='i';done()";
+ s.defer = true;
+ document.body.appendChild(s);
+
+ res+='4';
+}
+
+function done() {
+ is(res, "AacBCDEFGeHIJb1M2g3i", "scripts executed in the wrong order");
+ ok(scriptInsertedExternalExecuted, "Dynamic script did not block load");
+ SimpleTest.finish();
+}
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=28293">Mozilla Bug 28293</a>
+
+<script defer="defer">
+res += 'a';
+</script>
+<script defer="defer" src="data:text/plain,res+='b'"></script>
+<script defer="defer">
+res += 'c';
+</script>
+<script>
+res += 'B';
+</script>
+<script>
+res += 'C';
+
+s = document.createElement('script');
+s.textContent="res+='D';";
+document.body.appendChild(s);
+
+res += 'E';
+</script>
+<script>
+res += 'F';
+document.addEventListener("DOMContentLoaded", function() {
+ res += '1'
+ s = document.createElement('script');
+ s.src="file_bug28293.sjs?res+='M';";
+ document.body.appendChild(s);
+});
+res += 'G';
+</script>
+<script defer="defer">
+res += 'e';
+</script>
+<script src="file_bug28293.sjs?res+='H';"></script>
+<script>
+<![CDATA[
+res += 'I';
+s = document.createElement('script');
+s.src="file_bug28293.sjs?scriptInsertedExternalExecuted=true;";
+document.body.appendChild(s);
+res += 'J';
+]]>
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug298064.html b/dom/base/test/test_bug298064.html
new file mode 100644
index 0000000000..6fd21e5129
--- /dev/null
+++ b/dom/base/test/test_bug298064.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=298064
+-->
+<head>
+ <title>Test for Bug 298064</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=298064">Mozilla Bug 298064</a>
+<p id="display"><iframe src="bug298064-subframe.html"></iframe></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 298064 **/
+SimpleTest.waitForExplicitFinish()
+addLoadEvent(function() {
+ window.frames[0].test_func();
+});
+addLoadEvent(SimpleTest.finish);
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug300992.html b/dom/base/test/test_bug300992.html
new file mode 100644
index 0000000000..c9059bea85
--- /dev/null
+++ b/dom/base/test/test_bug300992.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=300992
+-->
+<head>
+ <title>Test for Bug 300992</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=300992">Mozilla Bug 300992</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 300992 **/
+SimpleTest.waitForExplicitFinish();
+
+var i = 0;
+var states = ['loading',
+ 'interactive1', 'interactive2',
+ 'complete1', 'complete2'];
+
+is(document.readyState, states[i++], 'initial readyState');
+document.onreadystatechange = function (event) {
+ is(document.readyState + '1', states[i++], 'readystatechange event "on" handler');
+};
+document.addEventListener('readystatechange', function(event) {
+ is(document.readyState + '2', states[i++], 'readystatechange event document listener');
+});
+window.addEventListener('readystatechange', function(event) {
+ ok(false, 'window listener', 'readystatechange event should not bubble to window');
+});
+addLoadEvent(function() {
+ is(i, states.length, 'readystatechange event count');
+ SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug311681.xml b/dom/base/test/test_bug311681.xml
new file mode 100644
index 0000000000..23efcb4688
--- /dev/null
+++ b/dom/base/test/test_bug311681.xml
@@ -0,0 +1,103 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=311681
+-->
+<head>
+ <title>Test for Bug 311681</title>
+ <script type="text/javascript" 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=311681">Mozilla Bug 311681</a>
+<script class="testbody" type="text/javascript">
+<![CDATA[
+ // Setup script
+ SimpleTest.waitForExplicitFinish();
+
+ // Make sure to trigger the hashtable case by asking for enough elements
+ // by ID.
+ for (var i = 0; i < 256; ++i) {
+ var x = document.getElementById(i);
+ }
+
+ // save off the document.getElementById function, since getting it as a
+ // property off the document it causes a content flush.
+ var fun = document.getElementById;
+
+ // Slot for our initial element with id "content"
+ var testNode;
+
+ function getCont() {
+ return fun.call(document, "content");
+ }
+
+ function testClone() {
+ // Test to make sure that if we have multiple nodes with the same ID in
+ // a document we don't forget about one of them when the other is
+ // removed.
+ var newParent = $("display");
+ var node = testNode.cloneNode(true);
+ isnot(node, testNode, "Clone should be a different node");
+
+ newParent.appendChild(node);
+
+ // Check what getElementById returns, no flushing
+ is(getCont(), node, "Should be getting orig node pre-flush 1");
+
+ // Trigger a layout flush, just in case.
+ var itemHeight = newParent.offsetHeight/10;
+
+ // Check what getElementById returns now.
+ is(getCont(), node, "Should be getting new node post-flush 1");
+
+ clear(newParent);
+
+ // Check what getElementById returns, no flushing
+ is(getCont(), testNode, "Should be getting orig node pre-flush 2");
+
+ // Trigger a layout flush, just in case.
+ var itemHeight = newParent.offsetHeight/10;
+
+ // Check what getElementById returns now.
+ is(getCont(), testNode, "Should be getting orig node post-flush 2");
+
+ node = testNode.cloneNode(true);
+ newParent.appendChild(node);
+ testNode.parentNode.removeChild(testNode);
+
+ // Check what getElementById returns, no flushing
+ is(getCont(), node, "Should be getting clone pre-flush");
+
+ // Trigger a layout flush, just in case.
+ var itemHeight = newParent.offsetHeight/10;
+
+ // Check what getElementById returns now.
+ is(getCont(), node, "Should be getting clone post-flush");
+
+ }
+
+ function clear(node) {
+ while (node.hasChildNodes()) {
+ node.removeChild(node.firstChild);
+ }
+ }
+
+ addLoadEvent(testClone);
+ addLoadEvent(SimpleTest.finish);
+]]>
+</script>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <script class="testbody" type="text/javascript">
+ <![CDATA[
+ testNode = fun.call(document, "content");
+ // Needs incremental XML parser
+ isnot(testNode, null, "Should have node here");
+ ]]>
+ </script>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug313646.html b/dom/base/test/test_bug313646.html
new file mode 100644
index 0000000000..55bb760978
--- /dev/null
+++ b/dom/base/test/test_bug313646.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=313646
+-->
+<head>
+ <title>Test for Bug 313646</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=313646">Mozilla Bug 313646</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 313646 **/
+
+// dom/base/test/bug313646.txt
+
+SimpleTest.waitForExplicitFinish();
+
+var count1 = 0;
+var count2 = 0;
+var count3 = 0;
+var count4 = 0;
+var innerXHRDone = 0;
+var req = new XMLHttpRequest();
+req.onreadystatechange = function(evt) {
+ ++window["count" + evt.target.readyState];
+
+ // Do something a bit evil, start a new sync XHR in
+ // readyStateChange listener.
+ var innerXHR = new XMLHttpRequest();
+ innerXHR.onreadystatechange = function(e) {
+ if (e.target.readyState == 4) {
+ ++innerXHRDone;
+ }
+ }
+ innerXHR.open("GET","bug313646.txt", false);
+ innerXHR.send();
+}
+
+// make the synchronous request
+req.open("GET","bug313646.txt", false);
+req.send();
+
+ok(count1, "XMLHttpRequest wasn't in state 1");
+is(count2, 0, "XMLHttpRequest shouldn't have been in state 2");
+is(count3, 0, "XMLHttpRequest shouldn't have been in state 3");
+ok(count4, "XMLHttpRequest wasn't in state 4");
+is(innerXHRDone, 2, "There should have been 2 inner XHRs.");
+
+SimpleTest.finish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug320799.html b/dom/base/test/test_bug320799.html
new file mode 100644
index 0000000000..dd7f598a0f
--- /dev/null
+++ b/dom/base/test/test_bug320799.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=320799
+-->
+<head>
+ <title>Test for Bug 320799</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=320799">Mozilla Bug 320799</a>
+<p id="display">
+ <select id="s" style="width: 100px; box-sizing: border-box; border: 0">
+ <option>This is a test, it really is a test I tell you</option>
+ </select>
+ <select id="s2">
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ <option>x</option>
+ </select>
+ <select id="s3">
+ <option>x</option>
+ </select>
+ <select id="s4" style="width: 100px; box-sizing: border-box; border: 0; margin: 10px">
+ <option>This is a test, it really is a test I tell you</option>
+ </select>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 320799 **/
+is($("s").scrollWidth, 100, "Scroll width should not include dropdown contents");
+is($("s2").clientWidth, $("s3").clientWidth,
+ "Client width should not depend on the dropdown's vertical scrollbar");
+
+is($("s4").scrollWidth, 100, "Scroll width should not include dropdown contents");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug322317.html b/dom/base/test/test_bug322317.html
new file mode 100644
index 0000000000..d4e7b6f853
--- /dev/null
+++ b/dom/base/test/test_bug322317.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=322317
+-->
+<head>
+ <title>Test for Bug 322317</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=322317">Mozilla Bug 322317</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 322317 **/
+/* Test that this does not throw exceptions */
+var http =new XMLHttpRequest();
+http.open("GET", window.location.href);
+http.send(null);
+http.open("GET", window.location.href);
+http.send(null);
+is(1, 1, "Got here, yay!");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug326337.html b/dom/base/test/test_bug326337.html
new file mode 100644
index 0000000000..fc789018cb
--- /dev/null
+++ b/dom/base/test/test_bug326337.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=326337
+-->
+<head>
+ <title>Test for Bug 326337</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=326337">Mozilla Bug 326337</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 326337 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var win = window.open("file_bug326337_outer.html", "", "width=10, height=10");
+
+function finishTest(str) {
+ win.close();
+ is(str, "#done", "failed to run");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug331959.html b/dom/base/test/test_bug331959.html
new file mode 100644
index 0000000000..c098c55d7b
--- /dev/null
+++ b/dom/base/test/test_bug331959.html
@@ -0,0 +1,151 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=331959
+-->
+<head>
+ <title>Test for Bug 331959</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=331959">Mozilla Bug 331959</a>
+<p id="display">
+ <iframe id="link-in-link-mouse"></iframe>
+ <iframe id="link-in-link-keyboard"></iframe>
+ <iframe id="input-in-link-mouse"></iframe>
+ <iframe id="input-in-link-keyboard"></iframe>
+ <iframe id="button-in-link-mouse"></iframe>
+ <iframe id="button-in-link-keyboard"></iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 331959 **/
+SimpleTest.waitForExplicitFinish();
+
+const FAILURL = "FAIL.html";
+const PASSURL = "PASS.html";
+
+var currentTest = 0;
+var tests = [ testLinkInLinkMouse, testLinkInLinkKeyboard,
+ testInputInLinkMouse, testInputInLinkKeyboard,
+ testButtonInLinkMouse, testButtonInLinkKeyboard ];
+function doNextTest() {
+ if (currentTest == tests.length) {
+ SimpleTest.finish();
+ } else {
+ tests[currentTest++]();
+ }
+}
+
+function generateLinkInLink(id, desc) {
+ var doc = $(id).contentDocument;
+ var outerA = doc.createElement("a");
+ var innerA = doc.createElement("a");
+ outerA.id = "outer";
+ innerA.id = "inner";
+ innerA.href = PASSURL;
+ outerA.href = FAILURL;
+ innerA.appendChild(doc.createTextNode("Text"));
+ outerA.appendChild(innerA);
+ doc.body.appendChild(outerA);
+ $(id).onload = function() {
+ is(this.contentDocument.documentElement.innerText, "PASS", desc);
+ // Have to remove the iframe we used from the DOM, because the harness is
+ // stupid and doesn't have enough space for more than one iframe.
+ $(id).remove();
+ doNextTest();
+ };
+ return [innerA, $(id).contentWindow];
+}
+
+function testLinkInLinkMouse() {
+ var [innerA, testWin] =
+ generateLinkInLink("link-in-link-mouse",
+ "Clicking an inner link should load the inner link");
+ synthesizeMouseAtCenter(innerA, {}, testWin);
+}
+
+function testLinkInLinkKeyboard() {
+ var [innerA, testWin] =
+ generateLinkInLink("link-in-link-keyboard",
+ "Hitting enter on an inner link should load the inner link");
+ innerA.focus();
+ synthesizeKey("VK_RETURN", {}, testWin);
+}
+
+function generateInputInLink(id, desc) {
+ var doc = $(id).contentDocument;
+ doc.body.innerHTML =
+ "<form action='" + PASSURL + "'><a href='" + FAILURL +
+ "'><input type='submit' id='submit'>";
+ $(id).onload = function() {
+ is(this.contentDocument.documentElement.innerText, "PASS", desc);
+ // Have to remove the iframe we used from the DOM, because the harness is
+ // stupid and doesn't have enough space for more than one iframe.
+ $(id).remove();
+ doNextTest();
+ };
+ var input = doc.getElementById("submit");
+ doc.body.offsetWidth;
+ return [input, $(id).contentWindow];
+}
+
+function testInputInLinkMouse() {
+ var [input, testWin] =
+ generateInputInLink("input-in-link-mouse",
+ "Clicking an submit input inside an anchor should submit the form");
+ synthesizeMouseAtCenter(input, {}, testWin);
+}
+
+function testInputInLinkKeyboard() {
+ var [input, testWin] =
+ generateInputInLink("input-in-link-keyboard",
+ "Return on submit input inside an anchor should submit the form");
+ input.focus();
+ synthesizeKey("VK_RETURN", {}, testWin);
+}
+
+function generateButtonInLink(id, desc) {
+ var doc = $(id).contentDocument;
+ doc.body.innerHTML =
+ "<form action='" + PASSURL + "'><a href='" + FAILURL +
+ "'><button type='submit' id='submit'>Submit</button>";
+ $(id).onload = function() {
+ is(this.contentDocument.documentElement.innerText, "PASS", desc);
+ // Have to remove the iframe we used from the DOM, because the harness is
+ // stupid and doesn't have enough space for more than one iframe.
+ $(id).remove();
+ doNextTest();
+ };
+ var button = doc.getElementById("submit");
+ return [button, $(id).contentWindow];
+}
+
+function testButtonInLinkMouse() {
+ var [button, testWin] =
+ generateButtonInLink("button-in-link-mouse",
+ "Clicking an submit button inside an anchor should submit the form");
+ synthesizeMouseAtCenter(button, {}, testWin);
+}
+
+function testButtonInLinkKeyboard() {
+ var [button, testWin] =
+ generateButtonInLink("button-in-link-keyboard",
+ "Return on submit button inside an anchor should submit the form");
+ button.focus();
+ synthesizeKey("VK_RETURN", {}, testWin);
+}
+
+// We need focus to handle clicks properly
+SimpleTest.waitForFocus(doNextTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug333064.html b/dom/base/test/test_bug333064.html
new file mode 100644
index 0000000000..65cc893a42
--- /dev/null
+++ b/dom/base/test/test_bug333064.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=333064
+-->
+<head>
+ <title>Test for Bug 333064</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=333064">Mozilla Bug 333064</a>
+<p id="display"></p>
+
+<div id="display">
+</div>
+<div id="korean-text">안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안안</div>
+
+<pre id="test">
+</pre>
+
+<script class="testbody" type="application/javascript">
+
+/** Test for Bug 333064 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+ var div = document.getElementById("korean-text");
+ var sel = window.getSelection();
+
+ // Select text node in div.
+ var r = document.createRange();
+ r.setStart(div, 0);
+ r.setEnd(div, 1);
+ sel.addRange(r);
+
+ SimpleTest.waitForClipboard(
+ function compare(value) {
+ // Make sure we got the HTML flavour we asked for and that our
+ // string is included without additional spaces.
+ return value.includes("korean-text") && value.includes("안".repeat(160));
+ },
+ function setup() {
+ synthesizeKey("C", {accelKey: true});
+ },
+ function onSuccess() {
+ SimpleTest.finish();
+ },
+ function onFailure() {
+ SimpleTest.finish();
+ },
+ "text/html"
+ );
+});
+
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug333198.html b/dom/base/test/test_bug333198.html
new file mode 100644
index 0000000000..e1c09000e8
--- /dev/null
+++ b/dom/base/test/test_bug333198.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=333198
+-->
+<head>
+ <title>Test for Bug 333198</title>
+ <script src="/tests/SimpleTest/SimpleTest.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(runTest,0);">
+<iframe id="ifr"></iframe><br>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=333198">Mozilla Bug 333198</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 333198 **/
+
+var focusTester;
+var focusTester2;
+var focusCount = 0;
+var eventCount = 0;
+function clickHandler() {
+ ++eventCount;
+}
+
+function suppressEvents(suppress) {
+ SpecialPowers.DOMWindowUtils.suppressEventHandling(suppress);
+}
+
+function sendEvents() {
+ windowUtils = SpecialPowers.getDOMWindowUtils(window);
+ windowUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
+ windowUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
+
+ iframeUtils = SpecialPowers.getDOMWindowUtils(document.getElementById("ifr").contentWindow);
+ iframeUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
+ iframeUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
+}
+
+function runTest() {
+ window.focus();
+ focusTester = document.getElementsByTagName("input")[0];
+ focusTester.blur();
+ window.addEventListener("click", clickHandler, true);
+ var ifr = document.getElementById("ifr")
+ ifr.contentWindow.addEventListener("click", clickHandler, true);
+ sendEvents();
+ is(eventCount, 2, "Wrong event count(1)");
+ suppressEvents(true);
+ sendEvents();
+ is(eventCount, 2, "Wrong event count(2)");
+ suppressEvents(false);
+ sendEvents();
+ is(eventCount, 4, "Wrong event count(2)");
+
+ is(focusCount, 0, "Wrong focus count (1)");
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", window.location, false);
+ xhr.onload = function() {
+ focusTester.focus();
+ is(focusCount, 1, "Wrong focus count (2)");
+ focusTester.blur();
+ }
+ xhr.send();
+
+ focusTester.focus();
+ is(focusCount, 2, "Wrong focus count (3)");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<input type="text" onfocus="++focusCount;">
+</body>
+</html>
diff --git a/dom/base/test/test_bug333673.html b/dom/base/test/test_bug333673.html
new file mode 100644
index 0000000000..2e8547b56c
--- /dev/null
+++ b/dom/base/test/test_bug333673.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=333673
+-->
+<head>
+ <title>Test for Bug 333673</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=333673">Mozilla Bug 333673</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 333673 **/
+
+is(document.implementation, document.implementation,
+ "document.implementation should be the same object all the time.");
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug337631.html b/dom/base/test/test_bug337631.html
new file mode 100644
index 0000000000..ad8d4e3d5a
--- /dev/null
+++ b/dom/base/test/test_bug337631.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=337631
+-->
+<head>
+ <title>Test for Bug 337631</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=337631">Mozilla Bug 337631</a>
+<p id="display"></p>
+<div id="content">
+
+<a href="foo" id="test4">foo</a>
+<input id="test1" value="test">
+<p id="test2">adsf<a href="#" id="test3">asdf</a><input id="test5"></p>
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 337631 **/
+
+function getActiveElement()
+{
+ var rv;
+
+ var el = document.activeElement;
+ if (!el) {
+ rv = "none";
+ return rv;
+ }
+
+ if (el && el != document.documentElement) {
+ var nt;
+ try {
+ nt = el.nodeType;
+ } catch (e) {
+ rv = "[no permission]";
+ return rv;
+ }
+ if (!nt) {
+ rv = "[unknown]";
+ } else if (nt == 1) {
+ rv = el.tagName;
+ } else if (nt == 3) {
+ rv = "textnode"
+ } else {
+ rv = nt;
+ }
+
+ el = el.parentNode;
+ while (el && el != document.documentElement) {
+ rv += " in ";
+ try {
+ nt = el.nodeType;
+ } catch (e) {
+ rv += "[no permission]";
+ return rv;
+ }
+ if (!nt) {
+ rv += "[unknown]";
+ } else if (nt == 1) {
+ rv += el.tagName;
+ } else if (nt == 3) {
+ rv += "textnode"
+ } else {
+ rv += nt;
+ }
+
+ el = el.parentNode;
+ }
+ }
+
+ return rv;
+}
+
+$('test1').focus();
+is(getActiveElement(), "INPUT in DIV in BODY", "getActiveElement tests");
+
+$('test2').focus();
+is(getActiveElement(), "INPUT in DIV in BODY", "getActiveElement tests");
+
+$('test3').focus();
+is(getActiveElement(), "A in P in DIV in BODY", "getActiveElement tests");
+
+$('test4').focus();
+is(getActiveElement(), "A in DIV in BODY", "getActiveElement tests");
+
+$('test5').focus();
+is(getActiveElement(), "INPUT in P in DIV in BODY", "getActiveElement tests");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug338541.xhtml b/dom/base/test/test_bug338541.xhtml
new file mode 100644
index 0000000000..9a83332a13
--- /dev/null
+++ b/dom/base/test/test_bug338541.xhtml
@@ -0,0 +1,49 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=338541
+-->
+<head>
+ <title>Test for Bug 338541</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=338541">Mozilla Bug 338541</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 338541 **/
+function getName(aNode, f)
+{
+ return (aNode ? aNode.nodeName : "(null)");
+}
+
+function walkDOM()
+{
+ var walker = document.createTreeWalker($('content'), NodeFilter.SHOW_ELEMENT, null);
+ var output = "";
+ while (walker.nextNode())
+ {
+ output += getName(walker.currentNode) + "\n";
+ }
+ output += "Final currentNode: " + getName(walker.currentNode);
+ is(output, "foo\nbar\nhtml:b\nqux\nbaz\nFinal currentNode: baz","treewalker returns correct nodeName");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(walkDOM, ok);
+
+</script>
+</pre>
+<div id="content" style="display: none">
+ <foo xmlns="http://example.com">
+ <bar><html:b xmlns:html="http://www.w3.org/1999/xhtml"><qux/></html:b>
+ <baz/>
+ </bar>
+ </foo>
+</div>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug338583.html b/dom/base/test/test_bug338583.html
new file mode 100644
index 0000000000..a399dd490c
--- /dev/null
+++ b/dom/base/test/test_bug338583.html
@@ -0,0 +1,665 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=338583
+-->
+<head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <title>Test for Bug 338583</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 bgColor=white>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=338583">Mozilla Bug 338583</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Tests for Bug 338583 **/
+
+// we test:
+// 1) the EventSource behaviour
+// 2) if the events are trusted
+// 3) possible invalid eventsources
+// 4) the close method when the object is just been used
+// 5) access-control
+// 6) the data parameter
+// 7) delayed server responses
+
+// --
+
+ var gTestsHaveFinished = [];
+
+ function setTestHasFinished(test_id)
+ {
+ if (gTestsHaveFinished[test_id]) {
+ return;
+ }
+
+ gTestsHaveFinished[test_id] = true;
+ for (var i=0; i < gTestsHaveFinished.length; ++i) {
+ if (!gTestsHaveFinished[i]) {
+ return;
+ }
+ }
+
+ SimpleTest.finish();
+ }
+
+ function runAllTests() {
+ // these tests run asynchronously, and they will take 8000 ms
+ var all_tests = [
+ doTest1, doTest1_e, doTest1_f, doTest2, doTest3, doTest3_b, doTest3_c, doTest3_d,
+ doTest3_e, doTest3_f, doTest3_g, doTest3_h, doTest4, doTest4_b,
+ doTest5, doTest5_b, doTest5_c, doTest5_e, doTest6, doTest7
+ ];
+
+ for (let test_id=0; test_id < all_tests.length; ++test_id) {
+ gTestsHaveFinished[test_id] = false;
+ var fn = all_tests[test_id];
+ fn(test_id);
+ }
+
+ setTimeout(function() {
+ for (let test_id=0; test_id < all_tests.length; ++test_id) {
+ if (!gTestsHaveFinished[test_id]) {
+ ok(false, "Test " + test_id + " took too long");
+ setTestHasFinished(test_id);
+ }
+ }
+ }, 60000 * stress_factor); // all tests together are supposed to take less than 1 minute
+ }
+
+ function fn_onmessage(e) {
+ if (e.currentTarget == e.target && e.target.hits != null)
+ e.target.hits.fn_onmessage++;
+ }
+
+ function fn_event_listener_message(e) {
+ if (e.currentTarget == e.target && e.target.hits != null)
+ e.target.hits.fn_event_listener_message++;
+ }
+
+ function fn_other_event_name(e) {
+ if (e.currentTarget == e.target && e.target.hits != null)
+ e.target.hits.fn_other_event_name++;
+ }
+
+ var gEventSourceObj1 = null, gEventSourceObj1_e, gEventSourceObj1_f;
+ var gEventSourceObj2 = null;
+ var gEventSourceObj3_a = null, gEventSourceObj3_b = null,
+ gEventSourceObj3_c = null, gEventSourceObj3_d = null,
+ gEventSourceObj3_e = null, gEventSourceObj3_f = null,
+ gEventSourceObj3_g = null, gEventSourceObj3_h = null;
+ var gEventSourceObj4_a = null, gEventSourceObj4_b = null;
+ var gEventSourceObj5_a = null, gEventSourceObj5_b = null,
+ gEventSourceObj5_c = null, gEventSourceObj5_d = null,
+ gEventSourceObj5_e = null, gEventSourceObj5_f = null;
+ var gEventSourceObj6 = null;
+ var gEventSourceObj7 = null;
+ var stress_factor; // used in the setTimeouts in order to help
+ // the test when running in slow machines
+
+ function hasBeenHitFor1And2(obj, min) {
+ if (obj.hits.fn_onmessage < min ||
+ obj.hits.fn_event_listener_message < min ||
+ obj.hits.fn_other_event_name < min)
+ return false;
+ return true;
+ }
+
+// in order to test (1):
+// a) if the EventSource constructor parameter is equal to its url attribute
+// b) let its fn_onmessage, fn_event_listener_message, and fn_other_event_name functions listeners be hit four times each
+// c) the close method (we expect readyState == CLOSED)
+// d) the close method (we expect no message events anymore)
+// e) use the default for withCredentials when passing dictionary arguments that don't explicitly set it
+// f) if a 204 HTTP response closes (interrupts) connections. See bug 869432.
+
+ function doTest1(test_id) {
+ gEventSourceObj1 = new EventSource("eventsource.resource");
+ ok(gEventSourceObj1.url == "http://mochi.test:8888/tests/dom/base/test/eventsource.resource", "Test 1.a failed.");
+ ok(gEventSourceObj1.readyState == 0 || gEventSourceObj1.readyState == 1, "Test 1.a failed.");
+
+ doTest1_b(test_id);
+ }
+
+ function doTest1_b(test_id) {
+ gEventSourceObj1.hits = [];
+ gEventSourceObj1.hits.fn_onmessage = 0;
+ gEventSourceObj1.onmessage = fn_onmessage;
+ gEventSourceObj1.hits.fn_event_listener_message = 0;
+ gEventSourceObj1.addEventListener('message', fn_event_listener_message, true);
+ gEventSourceObj1.hits.fn_other_event_name = 0;
+ gEventSourceObj1.addEventListener('other_event_name', fn_other_event_name, true);
+
+ // the eventsources.res always use a retry of 0.5 second, so for four hits a timeout of 6 seconds is enough
+ setTimeout(function(){
+ bhits = hasBeenHitFor1And2(gEventSourceObj1, 4);
+ ok(bhits, "Test 1.b failed.");
+
+ doTest1_c(test_id);
+ }, parseInt(6000*stress_factor));
+ }
+
+ function doTest1_c(test_id) {
+ gEventSourceObj1.close();
+ ok(gEventSourceObj1.readyState == 2, "Test 1.c failed.");
+
+ doTest1_d(test_id);
+ }
+
+ function doTest1_d(test_id) {
+ gEventSourceObj1.hits.fn_onmessage = 0;
+ gEventSourceObj1.hits.fn_event_listener_message = 0;
+ gEventSourceObj1.hits.fn_other_event_name = 0;
+
+ setTimeout(function(){
+ bhits = hasBeenHitFor1And2(gEventSourceObj1, 1);
+ ok(!bhits, "Test 1.d failed.");
+ gEventSourceObj1.close();
+ setTestHasFinished(test_id);
+ }, parseInt(2000*stress_factor));
+ }
+
+ function doTest1_e(test_id) {
+ try {
+ for (var options of [null, undefined, {}]) {
+ gEventSourceObj1_e = new EventSource("eventsource.resource", options);
+ is(gEventSourceObj1_e.withCredentials, false, "withCredentials should default to false");
+ gEventSourceObj1_e.close();
+ }
+ } catch (e) {
+ ok(false, "Test 1.e failed");
+ }
+ setTestHasFinished(test_id);
+ }
+
+ function doTest1_f(test_id) {
+ var called_on_error = false;
+
+ gEventSourceObj1_f = new EventSource("file_bug869432.eventsource");
+ gEventSourceObj1_f.onopen = function(e) {
+ ok(false, "Test 1.f failed: onopen was called");
+ };
+ gEventSourceObj1_f.onmessage = function(e) {
+ ok(false, "Test 1.f failed: onmessage was called");
+ };
+ gEventSourceObj1_f.onerror = function(e) {
+ if (called_on_error) {
+ ok(false, "Test 1.f failed: onerror was called twice");
+ }
+ called_on_error = true;
+ ok(gEventSourceObj1_f.readyState == 2, "Test 1.f failed: onerror was called with readyState = " + gEventSourceObj1_f.readyState);
+ };
+
+ setTimeout(function() { // just to clean...
+ ok(called_on_error, "Test 1.f failed: onerror was not called");
+ setTestHasFinished(test_id);
+ }, parseInt(5000*stress_factor));
+ }
+
+// in order to test (2)
+// a) set a eventsource that give the dom events messages
+// b) expect trusted events
+
+ function doTest2(test_id) {
+ var func = function(e) {
+ ok(e.isTrusted, "Test 2 failed");
+ gEventSourceObj2.close();
+ };
+
+ gEventSourceObj2 = new EventSource("eventsource.resource");
+ gEventSourceObj2.onmessage = func;
+
+ setTimeout(function() { // just to clean...
+ gEventSourceObj2.close();
+ setTestHasFinished(test_id);
+ }, parseInt(5000*stress_factor));
+ }
+
+// in order to test (3)
+// a) XSite domain error test
+// b) protocol file:// test
+// c) protocol javascript: test
+// d) wrong Content-Type test
+// e) bad http response code test
+// f) message eventsource without a data test
+// g) DNS error
+// h) EventSource which last message doesn't end with an empty line. See bug 710546
+
+ function doTest3(test_id) {
+ gEventSourceObj3_a = new EventSource("http://example.org/tests/dom/base/test/eventsource.resource");
+
+ gEventSourceObj3_a.onmessage = fn_onmessage;
+ gEventSourceObj3_a.hits = [];
+ gEventSourceObj3_a.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_a.hits.fn_onmessage == 0, "Test 3.a failed");
+ gEventSourceObj3_a.close();
+ setTestHasFinished(test_id);
+ }, parseInt(1500*stress_factor));
+ }
+
+ function doTest3_b(test_id) {
+ // currently no support yet for local files for b2g/Android mochitest, see bug 838726
+ if (navigator.appVersion.includes("Android") || SpecialPowers.Services.appinfo.name == "B2G") {
+ setTestHasFinished(test_id);
+ return;
+ }
+
+ var xhr = new XMLHttpRequest;
+ xhr.open("GET", "/dynamic/getMyDirectory.sjs", false);
+ xhr.send();
+ var basePath = xhr.responseText;
+
+ gEventSourceObj3_b = new EventSource("file://" + basePath + "eventsource.resource");
+
+ gEventSourceObj3_b.onmessage = fn_onmessage;
+ gEventSourceObj3_b.hits = [];
+ gEventSourceObj3_b.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_b.hits.fn_onmessage == 0, "Test 3.b failed");
+ gEventSourceObj3_b.close();
+ setTestHasFinished(test_id);
+ }, parseInt(1500*stress_factor));
+ }
+
+ function jsEvtSource()
+ {
+ return "event: message\n" +
+ "data: 1\n\n";
+ }
+
+ function doTest3_c(test_id) {
+ gEventSourceObj3_c = new EventSource("javascript: return jsEvtSource()");
+
+ gEventSourceObj3_c.onmessage = fn_onmessage;
+ gEventSourceObj3_c.hits = [];
+ gEventSourceObj3_c.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_c.hits.fn_onmessage == 0, "Test 3.c failed");
+ gEventSourceObj3_c.close();
+ setTestHasFinished(test_id);
+ }, parseInt(1500*stress_factor));
+ }
+
+ function doTest3_d(test_id) {
+ gEventSourceObj3_d = new EventSource("badContentType.eventsource");
+
+ gEventSourceObj3_d.onmessage = fn_onmessage;
+ gEventSourceObj3_d.hits = [];
+ gEventSourceObj3_d.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_d.hits.fn_onmessage == 0, "Test 3.d failed");
+ gEventSourceObj3_d.close();
+ setTestHasFinished(test_id);
+ }, parseInt(1500*stress_factor));
+ }
+
+ function doTest3_e(test_id) {
+ gEventSourceObj3_e = new EventSource("badHTTPResponseCode.eventsource");
+
+ gEventSourceObj3_e.onmessage = fn_onmessage;
+ gEventSourceObj3_e.hits = [];
+ gEventSourceObj3_e.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_e.hits.fn_onmessage == 0, "Test 3.e failed");
+ gEventSourceObj3_e.close();
+ setTestHasFinished(test_id);
+ }, parseInt(1500*stress_factor));
+ }
+
+ function doTest3_f(test_id) {
+ gEventSourceObj3_f = new EventSource("badMessageEvent.eventsource");
+
+ gEventSourceObj3_f.onmessage = fn_onmessage;
+ gEventSourceObj3_f.hits = [];
+ gEventSourceObj3_f.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_f.hits.fn_onmessage == 0, "Test 3.f failed");
+ gEventSourceObj3_f.close();
+ setTestHasFinished(test_id);
+ }, parseInt(1500*stress_factor));
+ }
+
+ function fnInvalidNCName() {
+ fnInvalidNCName.hits++;
+ }
+
+ function doTest3_g(test_id) {
+ gEventSourceObj3_g = new EventSource("http://hdfskjghsbg.jtiyoejowe.example.com");
+
+ gEventSourceObj3_g.onmessage = fn_onmessage;
+ gEventSourceObj3_g.hits = [];
+ gEventSourceObj3_g.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_g.hits.fn_onmessage == 0, "Test 3.g failed");
+ gEventSourceObj3_g.close();
+ setTestHasFinished(test_id);
+ }, parseInt(1500*stress_factor));
+ }
+
+ function fnMessageListenerTest3h(e) {
+ fnMessageListenerTest3h.msg_ok = (fnMessageListenerTest3h.msg_ok && e.data == "ok");
+ fnMessageListenerTest3h.id_ok = (fnMessageListenerTest3h.id_ok && e.lastEventId == "");
+ }
+
+ function doTest3_h(test_id) {
+ gEventSourceObj3_h = new EventSource("badMessageEvent2.eventsource");
+
+ gEventSourceObj3_h.addEventListener('message', fnMessageListenerTest3h, true);
+ fnMessageListenerTest3h.msg_ok = true;
+ fnMessageListenerTest3h.id_ok = true;
+
+ gEventSourceObj3_h.onmessage = fn_onmessage;
+ gEventSourceObj3_h.hits = [];
+ gEventSourceObj3_h.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj3_h.hits.fn_onmessage > 1, "Test 3.h.1 failed");
+ if (gEventSourceObj3_h.hits.fn_onmessage > 1) {
+ ok(fnMessageListenerTest3h.msg_ok, "Test 3.h.2 failed");
+ ok(fnMessageListenerTest3h.id_ok, "Test 3.h.3 failed");
+ }
+ gEventSourceObj3_h.close();
+ setTestHasFinished(test_id);
+ }, parseInt(6000*stress_factor));
+ }
+
+// in order to test (4)
+// a) close the object when it is in use, which is being processed and that is expected
+// to dispatch more eventlisteners
+// b) remove an eventlistener in use
+
+ function fn_onmessage4_a(e)
+ {
+ if (e.data > gEventSourceObj4_a.lastData)
+ gEventSourceObj4_a.lastData = e.data;
+ if (e.data == 2)
+ gEventSourceObj4_a.close();
+ }
+
+ function fn_onmessage4_b(e)
+ {
+ if (e.data > gEventSourceObj4_b.lastData)
+ gEventSourceObj4_b.lastData = e.data;
+ if (e.data == 2)
+ gEventSourceObj4_b.removeEventListener('message', fn_onmessage4_b, true);
+ }
+
+ function doTest4(test_id) {
+ gEventSourceObj4_a = new EventSource("forRemoval.resource");
+ gEventSourceObj4_a.lastData = 0;
+ gEventSourceObj4_a.onmessage = fn_onmessage4_a;
+
+ setTimeout(function() {
+ ok(gEventSourceObj4_a.lastData == 2, "Test 4.a failed");
+ gEventSourceObj4_a.close();
+ setTestHasFinished(test_id);
+ }, parseInt(3000*stress_factor));
+ }
+
+ function doTest4_b(test_id)
+ {
+ gEventSourceObj4_b = new EventSource("forRemoval.resource");
+ gEventSourceObj4_b.lastData = 0;
+ gEventSourceObj4_b.addEventListener('message', fn_onmessage4_b, true);
+
+ setTimeout(function() {
+ ok(gEventSourceObj4_b.lastData == 2, "Test 4.b failed");
+ gEventSourceObj4_b.close();
+ setTestHasFinished(test_id);
+ }, parseInt(3000*stress_factor));
+ }
+
+// in order to test (5)
+// a) valid access-control xsite request
+// b) invalid access-control xsite request
+// c) valid access-control xsite request on a restricted page with credentials
+// d) valid access-control xsite request on a restricted page without credentials
+// e) valid access-control xsite request on a restricted page when the parameter withCredentials is a getter
+// f) valid access-control xsite request on a restricted page when the parameter withCredentials is missing
+
+ function doTest5(test_id)
+ {
+ gEventSourceObj5_a = new EventSource("http://example.org/tests/dom/base/test/accesscontrol.resource");
+
+ gEventSourceObj5_a.onmessage = fn_onmessage;
+ gEventSourceObj5_a.hits = [];
+ gEventSourceObj5_a.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj5_a.hits.fn_onmessage != 0, "Test 5.a failed");
+ gEventSourceObj5_a.close();
+ setTestHasFinished(test_id);
+ }, parseInt(3000*stress_factor));
+ }
+
+ function doTest5_b(test_id)
+ {
+ gEventSourceObj5_b = new EventSource("http://example.org/tests/dom/base/test/invalid_accesscontrol.resource");
+
+ gEventSourceObj5_b.onmessage = fn_onmessage;
+ gEventSourceObj5_b.hits = [];
+ gEventSourceObj5_b.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj5_b.hits.fn_onmessage == 0, "Test 5.b failed");
+ gEventSourceObj5_b.close();
+ setTestHasFinished(test_id);
+ }, parseInt(3000*stress_factor));
+ }
+
+ function doTest5_c(test_id)
+ {
+ // credentials using the auth cache
+ var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+ // also, test mixed mode UI
+ xhr.open("GET", "https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_xhr", true, "user 1", "password 1");
+ xhr.send();
+ xhr.onloadend = function() {
+ ok(xhr.status == 200, "Failed to set credentials in test 5.c");
+
+ gEventSourceObj5_c = new EventSource("https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_evtsrc",
+ { withCredentials: true } );
+ ok(gEventSourceObj5_c.withCredentials, "Wrong withCredentials in test 5.c");
+
+ gEventSourceObj5_c.onmessage = function(e) {
+ ok(e.origin == "https://example.com", "Wrong Origin in test 5.c");
+ fn_onmessage(e);
+ };
+ gEventSourceObj5_c.hits = [];
+ gEventSourceObj5_c.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj5_c.hits.fn_onmessage > 0, "Test 5.c failed");
+ gEventSourceObj5_c.close();
+ doTest5_d(test_id);
+ }, parseInt(3000*stress_factor));
+ };
+ }
+
+ function doTest5_d(test_id)
+ {
+ var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+ xhr.open("GET", "https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_xhr", true, "user 2", "password 2");
+ xhr.send();
+ xhr.onloadend = function() {
+ ok(xhr.status == 200, "Failed to set credentials in test 5.d");
+
+ gEventSourceObj5_d = new EventSource("https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_evtsrc");
+ ok(!gEventSourceObj5_d.withCredentials, "Wrong withCredentials in test 5.d");
+
+ gEventSourceObj5_d.onmessage = function(e) {
+ ok(e.origin == "https://example.com", "Wrong Origin in test 5.d");
+ fn_onmessage(e);
+ };
+ gEventSourceObj5_d.hits = [];
+ gEventSourceObj5_d.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj5_d.hits.fn_onmessage == 0, "Test 5.d failed");
+ gEventSourceObj5_d.close();
+ setTestHasFinished(test_id);
+ }, parseInt(3000*stress_factor));
+ };
+ }
+
+ function doTest5_e(test_id)
+ {
+ // credentials using the auth cache
+ var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+ xhr.open("GET", "http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_xhr", true, "user 1", "password 1");
+ xhr.send();
+ xhr.onloadend = function() {
+ ok(xhr.status == 200, "Failed to set credentials in test 5.e");
+
+ gEventSourceObj5_e = new EventSource("http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_evtsrc",
+ { get withCredentials() { return true; } } );
+ ok(gEventSourceObj5_e.withCredentials, "Wrong withCredentials in test 5.e");
+
+ gEventSourceObj5_e.onmessage = function(e) {
+ ok(e.origin == "http://example.org", "Wrong Origin in test 5.e");
+ fn_onmessage(e);
+ };
+ gEventSourceObj5_e.hits = [];
+ gEventSourceObj5_e.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj5_e.hits.fn_onmessage > 0, "Test 5.e failed");
+ gEventSourceObj5_e.close();
+ doTest5_f(test_id);
+ }, parseInt(5000*stress_factor));
+ };
+ }
+
+ function doTest5_f(test_id)
+ {
+ var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+ xhr.open("GET", "http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_xhr", true, "user 2", "password 2");
+ xhr.send();
+ xhr.onloadend = function() {
+ ok(xhr.status == 200, "Failed to set credentials in test 5.f");
+
+ gEventSourceObj5_f = new EventSource("http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_evtsrc",
+ { });
+ ok(!gEventSourceObj5_f.withCredentials, "Wrong withCredentials in test 5.f");
+
+ gEventSourceObj5_f.onmessage = function(e) {
+ ok(e.origin == "http://example.org", "Wrong Origin in test 5.f");
+ fn_onmessage(e);
+ };
+ gEventSourceObj5_f.hits = [];
+ gEventSourceObj5_f.hits.fn_onmessage = 0;
+
+ setTimeout(function() {
+ ok(gEventSourceObj5_f.hits.fn_onmessage == 0, "Test 5.f failed");
+ gEventSourceObj5_f.close();
+ setTestHasFinished(test_id);
+ }, parseInt(3000*stress_factor));
+ };
+ }
+
+ function doTest6(test_id)
+ {
+ gEventSourceObj6 = new EventSource("somedatas.resource");
+ var fn_somedata = function(e) {
+ if (fn_somedata.expected == 0) {
+ ok(e.data == "123456789\n123456789123456789\n123456789123456789123456789123456789\n 123456789123456789123456789123456789123456789123456789123456789123456789\nçãá\"\'@`~à Ḿyyyy",
+ "Test 6.a failed");
+ } else if (fn_somedata.expected == 1) {
+ ok(e.data == " :xxabcdefghij\nçãá\"\'@`~à Ḿyyyy : zz",
+ "Test 6.b failed");
+ gEventSourceObj6.close();
+ } else {
+ ok(false, "Test 6 failed (unexpected message event)");
+ }
+ fn_somedata.expected++;
+ }
+ fn_somedata.expected = 0;
+ gEventSourceObj6.onmessage = fn_somedata;
+
+ setTimeout(function() {
+ gEventSourceObj6.close();
+ setTestHasFinished(test_id);
+ }, parseInt(2500*stress_factor));
+ }
+
+ function doTest7(test_id)
+ {
+ gEventSourceObj7 = new EventSource("delayedServerEvents.sjs");
+ gEventSourceObj7.msg_received = [];
+ gEventSourceObj7.onmessage = function(e)
+ {
+ e.target.msg_received.push(e.data);
+ }
+
+ setTimeout(function() {
+ gEventSourceObj7.close();
+
+ ok(gEventSourceObj7.msg_received[0] == "" &&
+ gEventSourceObj7.msg_received[1] == "delayed1" &&
+ gEventSourceObj7.msg_received[2] == "delayed2", "Test 7 failed");
+
+ document.getElementById('waitSpan').innerHTML = '';
+ setTestHasFinished(test_id);
+ }, parseInt(8000*stress_factor));
+ }
+
+ function doTest()
+ {
+ // Allow all cookies, then run the actual test
+ SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 0]]},
+ function() {
+ SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}],
+ doTestCallback);
+ });
+ }
+
+ function doTestCallback()
+ {
+
+ // we get a good stress_factor by testing 10 setTimeouts and some float
+ // arithmetic taking my machine as stress_factor==1 (time=589)
+
+ var begin_time = (new Date()).getTime();
+
+ var f = function() {
+ for (var j=0; j<f.i; ++j)
+ eval("Math.log(Math.atan(Math.sqrt(Math.pow(3.1415, 13.1415))/0.0007))");
+ if (f.i < 10) {
+ f.i++;
+ setTimeout(f, 10 + 10*f.i);
+ } else {
+ stress_factor = ((new Date()).getTime()-begin_time)*1/589;
+ stress_factor *= 1.50; // also, a margin of 50%
+
+ runAllTests();
+ }
+ }
+ f.i = 0;
+
+ setTimeout(f, 10);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ addLoadEvent(doTest);
+
+</script>
+</pre>
+ <span id=waitSpan>Wait please...</span>
+</body>
+</html>
diff --git a/dom/base/test/test_bug338679.html b/dom/base/test/test_bug338679.html
new file mode 100644
index 0000000000..bcc214f349
--- /dev/null
+++ b/dom/base/test/test_bug338679.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=338679
+-->
+<head>
+<title>Bug 338679: correct reporting of newValue/prevValue in
+ DOMAttrModified events</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=338679">Bug
+ 338679: correct reporting of newValue/prevValue in
+ DOMAttrModified events</a>
+
+<div id="test" style="width:20em"></div>
+
+<script>
+var testDiv = document.getElementById("test");
+var e_new, e_prev = testDiv.getAttribute("style");
+var phase, recursive = false;
+
+/* driver */
+var tests = [ test_1, test_2, test_3 ];
+var i = 0;
+function nextTest() {
+ if (i < tests.length) {
+ phase = tests[i];
+ i++;
+ phase();
+ } else {
+ SimpleTest.finish();
+ }
+}
+
+if (SpecialPowers.getBoolPref("dom.mutation-events.cssom.disabled")) {
+ ok(true, "DOMAttrModified event from CSSOM change is disabled");
+} else {
+ SimpleTest.waitForExplicitFinish();
+ testDiv.addEventListener("DOMAttrModified", attr_modified);
+ nextTest();
+}
+
+/* event handler */
+function attr_modified(ev) {
+ is(ev.newValue, e_new,
+ phase.name + (recursive ? " recursive" : "") + ": newValue");
+ is(ev.prevValue, e_prev,
+ phase.name + (recursive ? " recursive" : "") + ": prevValue");
+
+ e_prev = e_new;
+ if (!recursive) {
+ recursive = true;
+ e_new = "width: 0px;";
+ testDiv.style.width = "0";
+ } else {
+ recursive = false;
+ setTimeout(nextTest, 0);
+ }
+}
+
+/* tests */
+function test_1() {
+ e_new = "width: auto;";
+ testDiv.style.width = "auto";
+}
+
+function test_2() {
+ e_new = "width: 15%;";
+ testDiv.style.width = "15%";
+}
+
+function test_3() {
+ window.getComputedStyle(testDiv).width; // force style resolution
+ e_new = "width: inherit;";
+ testDiv.style.width = "inherit";
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug339494.html b/dom/base/test/test_bug339494.html
new file mode 100644
index 0000000000..dbf81f5e98
--- /dev/null
+++ b/dom/base/test/test_bug339494.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=339494
+-->
+<head>
+ <title>Test for Bug 339494</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=339494">Mozilla Bug 339494</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id="d"></div>
+ <div id="s"></div>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ /** Test for Bug 339494 **/
+
+ var d = document.getElementById("d");
+
+ d.setAttribute("hhh", "testvalue");
+
+ document.addEventListener("DOMAttrModified", removeItAgain);
+ d.removeAttribute("hhh");
+ document.removeEventListener("DOMAttrModified", removeItAgain);
+
+ function removeItAgain()
+ {
+ ok(!d.hasAttribute("hhh"), "Value check 1, there should be no value");
+ isnot(d.getAttribute("hhh"), "testvalue", "Value check 2");
+ document.removeEventListener("DOMAttrModified", removeItAgain);
+ d.removeAttribute("hhh");
+ ok(true, "Reachability, we shouldn't have crashed");
+ }
+
+ var s = document.getElementById("s");
+
+ s.setAttribute("ggg", "testvalue");
+
+ document.addEventListener("DOMAttrModified", compareVal);
+ s.setAttribute("ggg", "othervalue");
+ document.removeEventListener("DOMAttrModified", compareVal);
+
+ function compareVal()
+ {
+ ok(s.hasAttribute("ggg"), "Value check 3, there should be a value");
+ isnot(s.getAttribute("ggg"), "testvalue", "Value check 4");
+ is(s.getAttribute("ggg"), "othervalue", "Value check 5");
+ }
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug339494.xhtml b/dom/base/test/test_bug339494.xhtml
new file mode 100644
index 0000000000..985d78b368
--- /dev/null
+++ b/dom/base/test/test_bug339494.xhtml
@@ -0,0 +1,58 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=339494
+-->
+<head>
+ <title>Test for Bug 339494</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=339494">Mozilla Bug 339494</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id="d" />
+ <div id="s" />
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 339494 **/
+
+ var d = document.getElementById("d");
+
+ d.setAttribute("hhh", "testvalue");
+
+ document.addEventListener("DOMAttrModified", removeItAgain);
+ d.removeAttribute("hhh");
+ document.removeEventListener("DOMAttrModified", removeItAgain);
+
+ function removeItAgain()
+ {
+ ok(!d.hasAttribute("hhh"), "Value check 1, there should be no value");
+ isnot(d.getAttribute("hhh"), "testvalue", "Value check 2");
+ document.removeEventListener("DOMAttrModified", removeItAgain);
+ d.removeAttribute("hhh");
+ ok(true, "Reachability, We shouldn't have crashed");
+ }
+
+ var s = document.getElementById("s");
+
+ s.setAttribute("ggg", "testvalue");
+
+ document.addEventListener("DOMAttrModified", compareVal);
+ s.setAttribute("ggg", "othervalue");
+ document.removeEventListener("DOMAttrModified", compareVal);
+
+ function compareVal()
+ {
+ ok(s.hasAttribute("ggg"), "Value check 3, there should be a value");
+ isnot(s.getAttribute("ggg"), "testvalue", "Value check 4");
+ is(s.getAttribute("ggg"), "othervalue", "Value check 5");
+ }
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug343596.html b/dom/base/test/test_bug343596.html
new file mode 100644
index 0000000000..31a3e92820
--- /dev/null
+++ b/dom/base/test/test_bug343596.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=343596
+-->
+<head>
+ <title>Test for Bug 343596</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=343596">Mozilla Bug 343596</a>
+<p id="display"></p>
+<script id="foo"></script>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 343596 **/
+
+SimpleTest.waitForExplicitFinish();
+
+/** Cut error handling, because we're going to throw on purpose**/
+var errorHandler = window.onerror;
+window.onerror = null;
+
+
+try{
+ // Insert text into an empty script node that will cause a syntax error.
+ document.getElementById("foo").appendChild(document.createTextNode("("));
+}
+catch(ex){
+ // Note that this catch block does not execute.
+ ok(false, "this catch block should not execute");
+}
+
+setTimeout(function(){
+ok(true,"setTimeout still executes after bogus script insertion");
+window.error = errorHandler;
+SimpleTest.finish();}, 0);
+
+
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug345339.html b/dom/base/test/test_bug345339.html
new file mode 100644
index 0000000000..12baea6b25
--- /dev/null
+++ b/dom/base/test/test_bug345339.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=345339
+-->
+<head>
+ <title>Test for Bug 345339</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=345339">Mozilla Bug 345339</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+ <iframe id="testframe"
+ src="http://mochi.test:8888/tests/dom/base/test/345339_iframe.html">
+ </iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 345339 **/
+SimpleTest.waitForExplicitFinish();
+
+const testData = "Test data\n";
+let file = new File([testData],
+ "345339_test.file",
+ { type: "text/plain" });
+
+function afterLoad() {
+ var iframeDoc = $("testframe").contentDocument;
+
+ /* change all the form controls */
+ iframeDoc.getElementById("select").selectedIndex = 1;
+ iframeDoc.getElementById("radio2").checked = true;
+ iframeDoc.getElementById("password").value = "123456";
+ iframeDoc.getElementById("hidden").value = "gecko";
+
+ // Toggle the one field to a password type then text type like password
+ // visibility toggles on the web do.
+ iframeDoc.getElementById("passwordToggle").type = "password";
+ iframeDoc.getElementById("passwordToggle").value = "abcdef";
+ iframeDoc.getElementById("passwordToggle").type = "";
+
+ SpecialPowers.wrap(iframeDoc).getElementById("file").mozSetFileArray([file]);
+
+ /* Reload the page */
+ $("testframe").setAttribute("onload", "afterReload()");
+ iframeDoc.location.reload();
+}
+
+addLoadEvent(afterLoad);
+
+function afterReload() {
+ var iframeDoc = $("testframe").contentDocument;
+
+ is(iframeDoc.getElementById("select").selectedIndex, 1,
+ "select element selected index preserved");
+ is(iframeDoc.getElementById("radio1").checked, false,
+ "radio button #1 value preserved");
+ is(iframeDoc.getElementById("radio2").checked, true,
+ "radio button #2 value preserved");
+ isnot(iframeDoc.getElementById("password").value, "123456",
+ "password field value forgotten");
+ is(iframeDoc.getElementById("hidden").value, "gecko",
+ "hidden field value preserved");
+ is(iframeDoc.getElementById("passwordToggle").value, "",
+ "former password field value not saved");
+
+ // The new file object isn't ===, but it's extensionally equal:
+ let newFile = iframeDoc.getElementById("file").files[0];
+ for (let prop of ["name", "lastModified", "size", "type"]) {
+ is(newFile[prop], file[prop],
+ "file field " + prop + " property preserved");
+ }
+ let reader = new FileReader();
+ reader.onloadend = function() {
+ SimpleTest.finish();
+ };
+ reader.onload = function() {
+ is(reader.result, testData,
+ "file field contents preserved")
+ };
+ reader.onerror = function() {
+ is(reader.error, null,
+ "FileReader error");
+ };
+ reader.readAsText(newFile);
+}
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug346485.html b/dom/base/test/test_bug346485.html
new file mode 100644
index 0000000000..53f5587a5f
--- /dev/null
+++ b/dom/base/test/test_bug346485.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=346485
+-->
+<head>
+ <title>Test for Bug 346485</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=346485">Mozilla Bug 346485</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <input id='a'>
+ <input id='b'>
+ <output id='o' for='a b'></output>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 346485 **/
+
+/**
+ * This test is testing DOMTokenList used by the output element.
+ */
+
+function checkHtmlFor(htmlFor, list, msg) {
+ var length = htmlFor.length;
+ is(length, list.length, htmlFor + ": incorrect htmlFor length (" + msg + ")");
+ for (var i = 0; i < length; ++i) {
+ is(htmlFor[i], list[i], htmlFor + ": wrong element at " + i + " (" + msg + ")");
+ }
+}
+
+var o = document.getElementById('o');
+
+is(String(o.htmlFor), 'a b',
+ "htmlFor IDL attribute should reflect for content attribute");
+
+is(o.htmlFor.value, 'a b',
+ "value should return the underlying string");
+
+is(o.htmlFor.length, 2, "Size should be '2'");
+
+ok(o.htmlFor.contains('a'), "It should contain 'a' token'");
+ok(!o.htmlFor.contains('c'), "It should not contain 'c' token");
+
+is(o.htmlFor.item(0), 'a', "First item is 'a' token'");
+is(o.htmlFor.item(42), null, "Out-of-range should return null");
+
+o.htmlFor.add('c');
+checkHtmlFor(o.htmlFor, ['a', 'b', 'c'], "'c' token should have been added");
+
+o.htmlFor.add('a');
+checkHtmlFor(o.htmlFor, ['a', 'b', 'c'], "Nothing should have changed");
+
+o.htmlFor.remove('a');
+checkHtmlFor(o.htmlFor, ['b', 'c'], "'a' token should have been removed");
+
+o.htmlFor.remove('d');
+checkHtmlFor(o.htmlFor, ['b', 'c'], "Nothing should have been removed");
+
+o.htmlFor.toggle('a');
+checkHtmlFor(o.htmlFor, ['b', 'c', 'a'], "'a' token should have been added");
+
+o.htmlFor.toggle('b');
+checkHtmlFor(o.htmlFor, ['c', 'a'], "Nothing should have changed");
+
+o.htmlFor.value = "foo bar";
+checkHtmlFor(o.htmlFor, ['foo', 'bar'], "The underlying string should have changed");
+ok(o.htmlFor.contains('foo'), "It should contain 'foo'");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug352728.html b/dom/base/test/test_bug352728.html
new file mode 100644
index 0000000000..c5bc92da5c
--- /dev/null
+++ b/dom/base/test/test_bug352728.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=352728
+-->
+<head>
+ <title>Test for Bug 352728</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=352728">Mozilla Bug 352728</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 352728 **/
+
+function checkTypes(aNode, aNodeType, aTypeArray)
+{
+ for (var i = 0; i < aTypeArray.length; ++i) {
+ ok(aNode instanceof aTypeArray[i],
+ `${aNodeType} type test ${i}: ${aNodeType} should be a ${aTypeArray[i]}`);
+ }
+}
+
+function testCharacterData(aNode, aText)
+{
+ is(aNode.length, aText.length, "Text length should match");
+ is(aNode.data, aText, "Text content should match");
+ is(aNode.nodeValue, aText, "Check nodeValue");
+ is(aNode.localName, undefined, "Check localName")
+ is(aNode.namespaceURI, undefined, "Check namespaceURI");
+}
+
+function testComment(aText)
+{
+ try {
+ var comment = document.createComment(aText);
+ var types = [ Comment, CharacterData, Node ];
+ checkTypes(comment, "comment", types);
+
+ testCharacterData(comment, aText);
+ is(comment.nodeName, "#comment", "Check nodeName");
+ is(comment.nodeType, Node.COMMENT_NODE, "Check nodeType");
+ } catch (e) {
+ ok(0, "Correct functioning of comment stuff", "something broke: " + e);
+ }
+}
+
+function testCDATASection(aText, aShouldSucceed)
+{
+ try {
+ var cdataSection = document.createCDATASection(aText);
+ ok(0, "Invalid CDATA section creation",
+ "Shouldn't create CDATA sections in HTML");
+ } catch (e) {
+ is(e.name, "NotSupportedError", "Check exception");
+ is(e.code, DOMException.NOT_SUPPORTED_ERR, "Check exception code");
+ }
+}
+
+function testPI(aTarget, aData, aShouldSucceed, aReason)
+{
+ try {
+ var pi = document.createProcessingInstruction(aTarget, aData);
+ var types = [ ProcessingInstruction, Node ];
+ checkTypes(pi, "processing instruction", types);
+
+ is(pi.target, aTarget, "Check target");
+ is(pi.data, aData, "Check data");
+ is(pi.nodeName, aTarget, "Check nodeName");
+ is(pi.nodeValue, aData, "Check nodeValue");
+ is(pi.localName, undefined, "Check localName")
+ is(pi.namespaceURI, undefined, "Check namespaceURI");
+
+ is(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE, "Check nodeType");
+
+ if (!aShouldSucceed) {
+ ok(false, "Invalid processing instruction creation", aReason);
+ }
+ } catch (e) {
+ if (aShouldSucceed) {
+ ok(false, "Correct functioning of processing instruction stuff",
+ "something broke: " + e);
+ } else {
+ is(e.name, "InvalidCharacterError", "Check exception");
+ is(e.code, DOMException.INVALID_CHARACTER_ERR, "Check exception code");
+ }
+ }
+}
+
+testComment("Some text");
+testComment("Some text with a '-' in it");
+testComment("Some text with a '-' and a '-' and another '-'");
+testComment("Some text -- this should create a node!");
+testComment("<!-- This is an HTML comment -->");
+
+testCDATASection("Some text", true);
+testCDATASection("Some text with a '?' in it", true);
+testCDATASection("Some text with a '>' in it", true);
+testCDATASection("Some text with a '?' and a '>' in it", true);
+testCDATASection("Some text with a '? >' in it", true);
+testCDATASection("Some text -- ?> this should be ok", true);
+testCDATASection("Some text ]]&gt; this should not create a node!", false);
+
+testPI("foo", "bar", true);
+testPI("foo:bar", "baz", true);
+testPI("foo", "bar?", true);
+testPI("foo", "bar>", true);
+testPI("foo", "bar? >", true);
+testPI("<aaa", "bar", false, "Target should not contain '<'");
+testPI("aaa>", "bar", false, "Target should not contain '>'");
+testPI("aa?", "bar", false, "Target should not contain '?'");
+testPI("foo", "bar?>", false, "Data should not contain '?>'");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug352728.xhtml b/dom/base/test/test_bug352728.xhtml
new file mode 100644
index 0000000000..b868deb463
--- /dev/null
+++ b/dom/base/test/test_bug352728.xhtml
@@ -0,0 +1,188 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=352728
+-->
+<head>
+ <title>Test for Bug 352728</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=352728">Mozilla Bug 352728</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<!-- First make sure that a script consisting of multiple CDATA sections is
+ even supported -->
+<script class="testbody" type="text/javascript">
+ var cdataTest1 = false;
+ var cdataTest2 = false;
+ var cdataTest3 = false;
+</script>
+
+<script class="testbody" type="text/javascript">
+<![CDATA[
+ cdataTest1 = true;
+]]>
+ cdataTest2 = true;
+<![CDATA[
+ cdataTest3 = true;
+]]>
+</script>
+
+<script class="testbody" type="text/javascript">
+ is(cdataTest1, true, "Check first CDATA section");
+ is(cdataTest2, true, "Check in between CDATA sections");
+ is(cdataTest3, true, "Check second CDATA section");
+</script>
+
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+/** Test for Bug 352728 **/
+function checkTypes(aNode, aNodeType, aTypeArray)
+{
+ for (var i = 0; i < aTypeArray.length; ++i) {
+ ok(
+ aNode instanceof aTypeArray[i],
+ aNodeType + " type test " + i + " - " +
+ aNodeType + " should be a " + aTypeArray[i]
+ );
+ }
+}
+
+function checkInterfaces(aNode, aNodeType, aInterfaceArray)
+{
+ for (var i = 0; i < aInterfaceArray.length; ++i) {
+ ok(aNode instanceof SpecialPowers.Ci[aInterfaceArray[i]],
+ aNodeType + " interface test " + i + " - " +
+ aNodeType + " should be a " + aInterfaceArray[i]);
+ }
+}
+
+function testCharacterData(aNode, aText)
+{
+ is(aNode.length, aText.length, "Text length should match");
+ is(aNode.data, aText, "Text content should match");
+ is(aNode.nodeValue, aText, "Check nodeValue");
+ is(aNode.localName, undefined, "Check localName")
+ is(aNode.namespaceURI, undefined, "Check namespaceURI");
+}
+
+function testComment(aText)
+{
+ try {
+ var comment = document.createComment(aText);
+ var types = [ Comment, CharacterData, Node ];
+ checkTypes(comment, "comment", types);
+
+ var interfaces = [];
+ checkInterfaces(comment, "comment", interfaces);
+
+ testCharacterData(comment, aText);
+ is(comment.nodeName, "#comment", "Check nodeName");
+ is(comment.nodeType, Node.COMMENT_NODE, "Check nodeType");
+ } catch (e) {
+ ok(false, "Correct functioning of comment stuff - something broke: " + e);
+ }
+}
+
+function testCDATASection(aText, aShouldSucceed)
+{
+ try {
+ var cdataSection = document.createCDATASection(aText);
+ var types = [ CDATASection, CharacterData, Node ];
+ checkTypes(cdataSection, "CDATA section", types);
+
+ var interfaces = [];
+ checkInterfaces(cdataSection, "CDATA section", interfaces);
+
+ testCharacterData(cdataSection, aText);
+ is(cdataSection.nodeName, "#cdata-section", "Check nodeName");
+ is(cdataSection.nodeType, Node.CDATA_SECTION_NODE, "Check nodeType");
+
+ if (!aShouldSucceed) {
+ ok(0, "Invalid CDATA section creation - " +
+]]>
+ "Shouldn't create CDATA section with embedded \"]]&gt;\"");
+<![CDATA[
+ }
+ } catch (e) {
+ if (aShouldSucceed) {
+ ok(false,
+ "Correct functioning of CDATA section stuff - something broke: " + e);
+ } else {
+ is(e.name, "InvalidCharacterError", "Check exception");
+ is(e.code, DOMException.INVALID_CHARACTER_ERR, "Check exception code");
+ }
+ }
+}
+
+function testPI(aTarget, aData, aShouldSucceed, aReason)
+{
+ try {
+ var pi = document.createProcessingInstruction(aTarget, aData);
+ var types = [ ProcessingInstruction, Node ];
+ checkTypes(pi, "processing instruction", types);
+
+ var interfaces = [];
+ checkInterfaces(pi, "processing instruction", interfaces);
+
+ is(pi.target, aTarget, "Check target");
+ is(pi.data, aData, "Check data");
+ is(pi.nodeName, aTarget, "Check nodeName");
+ is(pi.nodeValue, aData, "Check nodeValue");
+ is(pi.localName, undefined, "Check localName")
+ is(pi.namespaceURI, undefined, "Check namespaceURI");
+
+ is(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE, "Check nodeType");
+
+ if (!aShouldSucceed) {
+ ok(false, "Invalid processing instruction creation - " + aReason);
+ }
+ } catch (e) {
+ if (aShouldSucceed) {
+ ok(false,
+ "Correct functioning of processing instruction stuff - " +
+ "something broke: " + e);
+ } else {
+ is(e.name, "InvalidCharacterError", "Check exception");
+ is(e.code, DOMException.INVALID_CHARACTER_ERR, "Check exception code");
+ }
+ }
+}
+
+testComment("Some text");
+testComment("Some text with a '-' in it");
+testComment("Some text with a '-' and a '-' and another '-'");
+testComment("Some text -- this should create a node!");
+testComment("<!-- This is an HTML comment -->");
+
+testCDATASection("Some text", true);
+testCDATASection("Some text with a '?' in it", true);
+testCDATASection("Some text with a '>' in it", true);
+testCDATASection("Some text with a '?' and a '>' in it", true);
+testCDATASection("Some text with a '? >' in it", true);
+testCDATASection("Some text -- ?> this should be ok", true);
+]]>
+testCDATASection("Some text ]]&gt; this should not create a node!", false);
+
+<![CDATA[
+
+testPI("foo", "bar", true);
+testPI("foo:bar", "baz", true);
+testPI("foo", "bar?", true);
+testPI("foo", "bar>", true);
+testPI("foo", "bar? >", true);
+testPI("<aaa", "bar", false, "Target should not contain '<'");
+testPI("aaa>", "bar", false, "Target should not contain '>'");
+testPI("aa?", "bar", false, "Target should not contain '?'");
+testPI("foo", "bar?>", false, "Data should not contain '?>'");
+]]>
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug353334.html b/dom/base/test/test_bug353334.html
new file mode 100644
index 0000000000..4fa30828a2
--- /dev/null
+++ b/dom/base/test/test_bug353334.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=353334
+-->
+<head>
+ <title>Test for Bug 353334</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>var x = "PASS"</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=353334">Mozilla Bug 353334</a>
+<p id="display">
+<iframe id="one"></iframe>
+<object id="two" data="about:blank"></object>
+<iframe id="three" srcdoc="<body>test</body>"></iframe>
+<object id="four" data="object_bug353334.html"></object>
+<iframe id="five" src="javascript:parent.x"></iframe>
+<object id="six" data="javascript:x"></object>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 353334 **/
+SimpleTest.waitForExplicitFinish();
+
+function doPrincipalTest(id) {
+ var doc = SpecialPowers.wrap($(id).contentDocument);
+
+ isnot(doc.nodePrincipal, undefined, "Should have a principal");
+ isnot(doc.nodePrincipal, null, "Should have a non-null principal");
+ is(doc.nodePrincipal.origin, SpecialPowers.wrap(document).nodePrincipal.origin,
+ "Wrong principal for document in node with id='" + id + "'");
+}
+
+function doContentTest(id) {
+ is($(id).contentDocument.documentElement.textContent, "PASS",
+ "Script executed in wrong context in node with id='" + id + "'");
+}
+
+function checkPrincipal() {
+ ok(SpecialPowers.call_Instanceof(SpecialPowers.wrap(document).nodePrincipal, SpecialPowers.Ci.nsIPrincipal),
+ "Should be a principal");
+}
+
+addLoadEvent(function() {
+ checkPrincipal();
+
+ for (var i of [ "one", "two", "three", "four" ]) {
+ doPrincipalTest(i);
+ }
+
+ for (i of [ "five", "six" ]) {
+ doContentTest(i);
+ }
+
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug355026.html b/dom/base/test/test_bug355026.html
new file mode 100644
index 0000000000..e5ace96970
--- /dev/null
+++ b/dom/base/test/test_bug355026.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test from Adam Guthrie.
+
+https://bugzilla.mozilla.org/show_bug.cgi?id=355026
+-->
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=355026">Mozilla Bug 355026</a>
+<div style="display: none" id="lengthtest">
+</div>
+<pre id="test">
+<script type="text/javascript">
+
+ var foo = document.createElement("div");
+ foo.appendChild(document.createElement("div"));
+ var children = foo.getElementsByTagName("div");
+
+ is(children.length, 1, "After appending a child div to a div, div.length should be 1.");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug357450.html b/dom/base/test/test_bug357450.html
new file mode 100644
index 0000000000..006768fa89
--- /dev/null
+++ b/dom/base/test/test_bug357450.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=357450
+-->
+
+<head>
+ <title>Test for Bug 357450</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="file_bug357450.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style type="text/css">
+
+ </style>
+</head>
+
+<body>
+
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=357450"
+ target="_blank" >Mozilla Bug 357450</a>
+
+<p id="display"></p>
+<span class="classtest">hmm</span>
+<span class="classtest">hmm</span>
+<div id="content" style="display: block">
+ <a name="nametest">hmm</a>
+ <b class="foo">hmm</b>
+ <b id="test1" class="test1">hmm</b>
+ <b id="test2" class="test2">hmm</b>
+ <b id="int-class" class="1">hmm</b>
+ <span class="classtest">hmm</span>
+ <div id="example">
+ <p id="p1" class="aaa bbb"/>
+ <p id="p2" class="aaa ccc"/>
+ <p id="p3" class="bbb ccc"/>
+ </div>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug357450.xhtml b/dom/base/test/test_bug357450.xhtml
new file mode 100644
index 0000000000..dee66f1cd1
--- /dev/null
+++ b/dom/base/test/test_bug357450.xhtml
@@ -0,0 +1,39 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=357450
+-->
+
+<head>
+ <title>Test for Bug 357450</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="file_bug357450.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=357450"
+ target="_blank">Mozilla Bug 357450</a>
+
+<p id="display"></p>
+<span class="classtest">hmm</span>
+<span class="classtest">hmm</span>
+
+<div id="content" style="display: block">
+ <a name="nametest">hmm</a>
+ <b class="foo">hmm</b>
+ <b id="test1" class="test1">hmm</b>
+ <b id="test2" class="test2">hmm</b>
+ <b id="int-class" class="1">hmm</b>
+ <span class="classtest">hmm</span>
+
+ <div id="example">
+ <p id="p1" class="aaa bbb"/>
+ <p id="p2" class="aaa ccc"/>
+ <p id="p3" class="bbb ccc"/>
+ </div>
+
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug357450_svg.xhtml b/dom/base/test/test_bug357450_svg.xhtml
new file mode 100644
index 0000000000..a1d8a528a7
--- /dev/null
+++ b/dom/base/test/test_bug357450_svg.xhtml
@@ -0,0 +1,46 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=357450
+-->
+
+<head>
+ <title>Test for Bug 357450</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="file_bug357450.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+</head>
+
+<body>
+
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=357450"
+ target="_blank">Mozilla Bug 357450</a>
+
+<p id="display"></p>
+<span class="classtest">hmm</span>
+<span class="classtest">hmm</span>
+<div id="content" style="display: block">
+ <a name="nametest">hmm</a>
+ <b class="foo">hmm</b>
+ <b id="test1" class="test1">hmm</b>
+ <b id="test2" class="test2">hmm</b>
+ <b id="int-class" class="1">hmm</b>
+ <svg xmlns="http://www.w3.org/2000/svg"
+ height="100" width="100" style="float:left">
+ <path d="M38,38c0-12,24-15,23-2c0,9-16,13-16,23v7h11v-4c0-9,17-12,17-27c-2-22-45-22-45,3zM45,70h11v11h-11z" fill="#371"/>
+
+ <circle cx="50" cy="50" r="45" class="classtest"
+ fill="none" stroke="#371" stroke-width="10"/>
+ </svg>
+
+ <div id="example">
+ <p id="p1" class="aaa bbb"/>
+ <p id="p2" class="aaa ccc"/>
+ <p id="p3" class="bbb ccc"/>
+ </div>
+
+</div>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug357509.html b/dom/base/test/test_bug357509.html
new file mode 100644
index 0000000000..d8b288c2fd
--- /dev/null
+++ b/dom/base/test/test_bug357509.html
@@ -0,0 +1,36 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=357509
+-->
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>
+ function foo(elem) {
+ rng = document.createRange();
+ rng.setStartBefore(elem);
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=357509">Mozilla Bug 357509</a>
+<div style="display: none" id="rangetest">
+</div>
+<pre id="test">
+<script type="text/javascript">
+var passed = false;
+try {
+ foo(document.getElementById("rangetest"))
+ passed = true;
+}
+catch (e) {
+ passed = false;
+}
+
+<!-- The ok() function tests the first arg -->
+ok(passed, "Range.setStartBefore");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug358660.html b/dom/base/test/test_bug358660.html
new file mode 100644
index 0000000000..4788b1824b
--- /dev/null
+++ b/dom/base/test/test_bug358660.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=358660
+-->
+<head>
+ <title>Test for Bug 358660</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=358660">Mozilla Bug 358660</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="testframe"
+ srcdoc="<html><body>Some text</body></html>"></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 358660 **/
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+ var doc = $("testframe").contentDocument;
+ var range = doc.createRange();
+ range.selectNode(doc.documentElement);
+ is(range.toString(), "Some text", "Check text");
+
+ SimpleTest.finish()
+}
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug362391.xhtml b/dom/base/test/test_bug362391.xhtml
new file mode 100644
index 0000000000..a00b8e52a8
--- /dev/null
+++ b/dom/base/test/test_bug362391.xhtml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:foobar="http://www.foobar.com">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=362391
+-->
+<head>
+ <title>Test for Bug 362391</title>
+ <!-- XHTML needs explicit script elements -->
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/Iter.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.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=362391">Mozilla Bug 362391</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="test1"/>
+<div id="test2"/>
+<div id="test3" attr="null"/>
+<div id="test4" foobar:attr="http://www.foobar.com"/>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 362391 **/
+
+ var currentTest = 0;
+ var expected = "";
+ function listener(evt) {
+ var r = document.getElementById("result");
+ ++currentTest;
+ ok(((evt.relatedNode.namespaceURI + "") == expected),
+ evt.relatedNode.namespaceURI + " == "+ expected);
+ }
+
+ document.addEventListener("DOMAttrModified", listener, true);
+
+ function test() {
+ expected = "null";
+ document.getElementById("test1")
+ .setAttribute("attr", "null");
+
+ expected = "http://www.foobar.com";
+ document.getElementById("test2")
+ .setAttributeNS("http://www.foobar.com", "attr", "http://www.foobar.com");
+
+ expected = "http://www.foobar.com";
+ document.getElementById("test3")
+ .setAttributeNS("http://www.foobar.com", "attr", "http://www.foobar.com");
+
+ expected = "null";
+ document.getElementById("test4")
+ .setAttribute("attr", "null");
+
+ expected = "http://www.foobar.com";
+ document.getElementById("test3")
+ .removeAttributeNS("http://www.foobar.com", "attr");
+
+ expected = "null";
+ document.getElementById("test4")
+ .removeAttribute("attr");
+ }
+
+ test();
+</script>
+</pre>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug364092.xhtml b/dom/base/test/test_bug364092.xhtml
new file mode 100644
index 0000000000..93ba2554ec
--- /dev/null
+++ b/dom/base/test/test_bug364092.xhtml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=364092
+-->
+<head>
+ <title>Test for Bug 364092</title>
+ <!-- XHTML needs explicit script elements -->
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/Iter.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.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=364092">Mozilla Bug 364092</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="test1" foo="foo"/>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 364092 **/
+
+ var test1 = document.getElementById("test1");
+ var attrNode = test1.getAttributeNode("foo");
+ function mutationHandler(aEvent) {
+ ok(attrNode == aEvent.relatedNode);
+ ok(!test1.hasAttribute("foo"));
+ }
+
+ function runTest() {
+ test1.addEventListener("DOMAttrModified", mutationHandler, true);
+ test1.removeAttributeNode(attrNode);
+ test1.removeEventListener("DOMAttrModified", mutationHandler, true);
+ }
+
+ runTest();
+</script>
+</pre>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug364413.xhtml b/dom/base/test/test_bug364413.xhtml
new file mode 100644
index 0000000000..4e4b20ea8c
--- /dev/null
+++ b/dom/base/test/test_bug364413.xhtml
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:foobar="http://www.foobar.com">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=364413
+-->
+<head>
+ <title>Test for Bug 364413</title>
+ <!-- XHTML needs explicit script elements -->
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/Iter.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.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=364413">Mozilla Bug 364413</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="test1" foobar:foo="foo"/>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 364413 **/
+
+ var test1 = document.getElementById("test1");
+ var attrNode = test1.getAttributeNodeNS("http://www.foobar.com", "foo");
+ function mutationHandler(aEvent) {
+ ok(attrNode == aEvent.relatedNode);
+ ok(aEvent.target == attrNode.ownerElement);
+ }
+
+ function runTest() {
+ test1.removeAttributeNode(attrNode);
+ test1.addEventListener("DOMAttrModified", mutationHandler, true);
+ test1.setAttributeNodeNS(attrNode);
+ test1.removeEventListener("DOMAttrModified", mutationHandler, true);
+ }
+
+ runTest();
+</script>
+</pre>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug366944.html b/dom/base/test/test_bug366944.html
new file mode 100644
index 0000000000..8e4acd9e3f
--- /dev/null
+++ b/dom/base/test/test_bug366944.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=366944
+-->
+<title>Test for Bug 366944</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=366944">Mozilla Bug 366944</a>
+<script>
+
+/** Test for Bug 366944 **/
+var testNodes = [document, document.doctype, document.createDocumentFragment()];
+for (var i = 0; i < testNodes.length; i++) {
+ var range = document.createRange();
+ // If a non-Text node is partially contained, we expect to throw for that
+ // first
+ range.setStart(document.head, 0);
+ range.setEnd(document.body, 0);
+ var threw = false;
+ var desc = " (surrounding a range with partially-contained Element "
+ + "with " + (i == 0 ? "document" : i == 1 ? "doctype" : "docfrag") + ")";
+ try {
+ range.surroundContents(testNodes[i]);
+ } catch(e) {
+ threw = true;
+ is(Object.getPrototypeOf(e), DOMException.prototype,
+ "Must throw DOMException" + desc);
+ is(e.name, "InvalidStateError", "Must throw InvalidStateError" + desc);
+ }
+ ok(threw, "Must throw" + desc);
+
+ range.setStart(document.body, 0);
+ range.setEnd(document.body, 1);
+ threw = false;
+ desc = " (surrounding a regular range "
+ + "with " + (i == 0 ? "document" : i == 1 ? "doctype" : "docfrag") + ")";
+ try {
+ range.surroundContents(testNodes[i]);
+ } catch(e) {
+ threw = true;
+ is(Object.getPrototypeOf(e), DOMException.prototype,
+ "Must throw DOMException" + desc);
+ is(e.name, "InvalidNodeTypeError",
+ "Must throw InvalidNodeTypeError" + desc);
+ }
+ ok(threw, "Must throw" + desc);
+}
+
+</script>
diff --git a/dom/base/test/test_bug366946.html b/dom/base/test/test_bug366946.html
new file mode 100644
index 0000000000..a8173828dc
--- /dev/null
+++ b/dom/base/test/test_bug366946.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=366946
+-->
+<head>
+ <title>Test for Bug 366946</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=366946">Mozilla Bug 366946</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id="1"></div>
+ <div id="2"></div>
+ <div id="3"></div>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ /** Test for Bug 366946 **/
+ SimpleTest.waitForExplicitFinish();
+
+ addLoadEvent(function() {
+ var doc1 = document;
+
+ // Set up a new document.
+ var doc2 = document.implementation.createDocument('', '', null);
+
+ // Copy some nodes into doc2
+ var node1 = doc2.importNode(doc1.getElementById('1'), false);
+ var node2 = doc2.importNode(doc1.getElementById('1'), false);
+ node1.appendChild(node2);
+ doc2.appendChild(node1);
+
+ // Create two ranges in doc1 to compare.
+ var range1 = doc1.createRange();
+ range1.setStart(doc1.getElementById('1'), 0);
+ range1.setEnd(doc1.getElementById('2'), 0);
+
+ var range2 = doc1.createRange();
+ range2.setStart(doc1.getElementById('2'), 0);
+ range2.setEnd(doc1.getElementById('3'), 0);
+
+ // Create a range in doc2.
+ var range3 = doc2.createRange();
+ range3.setStart(node1, 0);
+ range3.setEnd(node2, 0);
+
+ // Compare range1 and range2: Should return 1.
+ try {
+ var result1 = range2.compareBoundaryPoints(Range.START_TO_START, range1);
+ }
+ catch (ex) {
+ }
+ ok(result1 === 1, "range1 and range2 are compared correctly.");
+
+ // Compare range1 and range3: Should throw DOMException WRONG_DOCUMENT_ERR.
+ try {
+ var result2 = range3.compareBoundaryPoints(Range.START_TO_START, range1);
+ }
+ catch (ex) {
+ var error = ex.name;
+ var errorCode = ex.code;
+ }
+
+ ok(error == "WrongDocumentError",
+ "The WrongDocumentError exception thrown when comparing ranges from " +
+ "different documents ");
+ ok(errorCode == DOMException.WRONG_DOCUMENT_ERR,
+ "The exception thrown when comparing ranges from different documents " +
+ "has the code DOMException.WRONG_DOCUMENT_ERR");
+ ok(result2 === undefined, "range1 and range3 couldn't be compared as expected.");
+ SimpleTest.finish();
+ });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug367164.html b/dom/base/test/test_bug367164.html
new file mode 100644
index 0000000000..46dc4f779f
--- /dev/null
+++ b/dom/base/test/test_bug367164.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=367164
+-->
+<head>
+ <title>Test for Bug 367164</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=367164">Mozilla Bug 367164</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 367164 **/
+
+var span = document.createElement("span");
+
+var ins1 = false;
+var ins2 = false;
+var rem1 = false;
+var rem2 = false;
+
+span.addEventListener("DOMNodeInserted", function() { ins1 = true; }, true);
+span.addEventListener("DOMNodeInserted", function() { ins2 = true; });
+span.addEventListener("DOMNodeRemoved", function() { rem1 = true; }, true);
+span.addEventListener("DOMNodeRemoved", function() { rem2 = true; });
+
+$("content").appendChild(span);
+$("content").removeChild(span);
+
+is(ins1, true, "Capturing DOMNodeInserted listener");
+is(ins2, true, "Bubbling DOMNodeInserted listener");
+is(rem1, true, "Capturing DOMNodeRemoved listener");
+is(rem2, true, "Bubbling DOMNodeRemoved listener");
+
+</script>
+
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug368972.html b/dom/base/test/test_bug368972.html
new file mode 100644
index 0000000000..08a348b3cd
--- /dev/null
+++ b/dom/base/test/test_bug368972.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=368972
+-->
+<head>
+ <title>Test for Bug 368972</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<style type="text/css">
+#embed11, #object11 {
+ width: 400px;
+ height: 400px;
+}
+</style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=368972">Mozilla Bug 368972</a>
+<p id="display"></p>
+<div id="content">
+Embed without defined width/height:
+<embed id="embed1" type="bogus"><br>
+Embed width=0 height=0
+<embed id="embed2" type="bogus" width="0" height="0"><br>
+Embed width=100 height=100
+<embed id="embed3" type="bogus" width="100" height="100"><br>
+Embed height=100
+<embed id="embed4" type="bogus" height="100"><br>
+Embed width=100
+<embed id="embed5" type="bogus" width="100"><br>
+Embed width=100xxx height=100
+<embed id="embed6" type="bogus" width="100xxx" height="100"><br>
+Embed width=0100 height=100
+<embed id="embed7" type="bogus" width="0100" height="100"><br>
+Embed width= height=100
+<embed id="embed8" type="bogus" width="" height="100"><br>
+Embed width=100 height=100 style="width:400px"
+<embed id="embed9" type="bogus" width="100" height="100" style="width:400px;"><br>
+Embed height=100 style="width:400px"
+<embed id="embed10" type="bogus" height="100" style="width:400px;"><br>
+Embed height=100 (stylesheet width:400px height:400px)
+<embed id="embed11" type="bogus" height="100"><br>
+
+Object without defined width/height:
+<object id="object1" type="bogus">
+</object><br>
+Object width=0 height=0
+<object id="object2" type="bogus" width="0" height="0">
+</object><br>
+Object width=100 height=100
+<object id="object3" type="bogus" width="100" height="100">
+</object><br>
+Object height=100
+<object id="object4" type="bogus" height="100">
+</object><br>
+Object width=100
+<object id="object5" type="bogus" width="100">
+</object><br>
+Object width=100xxx height=100
+<object id="object6" type="bogus" width="100xxx" height="100">
+</object><br>
+Object width=0100 height=100
+<object id="object7" type="bogus" width="0100" height="100">
+</object><br>
+Object width= height=100
+<object id="object8" type="bogus" width="" height="100">
+</object><br>
+Object width=100 height=100 style="width:400px"
+<object id="object9" type="bogus" width="100" height="100" style="width:400px;">
+</object><br>
+Object height=100 style="width:400px"
+<object id="object10" type="bogus" height="100" style="width:400px;">
+</object><br>
+Object height=100 (stylesheet width:400px height:400px)
+<object id="object11" type="bogus" height="100">
+</object><br>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function check_size(id, width, height) {
+ var element = document.getElementById(id);
+ ok(element, "Plugin element " + id + " did not exist");
+ if (width != "auto") {
+ width = width + "px";
+ }
+ if (height != "auto") {
+ height = height + "px";
+ }
+ var style = window.getComputedStyle(element);
+ is(style.width, width, "Plugin element " + id + " had an incorrect width");
+ is(style.height, height, "Plugin element " + id + " had an incorrect height");
+}
+
+check_size("embed1", "auto", "auto");
+check_size("embed2", 0, 0);
+check_size("embed3", 100, 100);
+check_size("embed4", "auto", 100);
+check_size("embed5", 100, "auto");
+check_size("embed6", 100, 100);
+check_size("embed7", 100, 100);
+check_size("embed8", "auto", 100);
+check_size("embed9", 400, 100);
+check_size("embed10", 400, 100);
+check_size("embed11", 400, 400);
+
+check_size("object1", "auto", "auto");
+check_size("object2", 0, 0);
+check_size("object3", 100, 100);
+check_size("object4", "auto", 100);
+check_size("object5", 100, "auto");
+check_size("object6", 100, 100);
+check_size("object7", 100, 100);
+check_size("object8", "auto", 100);
+check_size("object9", 400, 100);
+check_size("object10", 400, 100);
+check_size("object11", 400, 400);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug371576-2.html b/dom/base/test/test_bug371576-2.html
new file mode 100644
index 0000000000..2a09118645
--- /dev/null
+++ b/dom/base/test/test_bug371576-2.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=371576
+-->
+<head id="head">
+ <title>Test for Bug 371576</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=371576">Mozilla Bug 371576</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ var result = "A";
+ var scrElem= document.createElement('script');
+ scrElem.textContent = 'result+="B";$("content").innerHTML="--";result+="C";';
+ $("head").appendChild(scrElem);
+ result += "D";
+
+</script>
+<script>result += "E"</script>
+<script>result += "F"</script>
+<script>is(result, "ABCDEF", "Wrong order of execution");</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug371576-3.html b/dom/base/test/test_bug371576-3.html
new file mode 100644
index 0000000000..ec91f7361c
--- /dev/null
+++ b/dom/base/test/test_bug371576-3.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=371576
+-->
+<head id="head">
+ <title>Test for Bug 371576</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=371576">Mozilla Bug 371576</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script src='data:text/javascript,
+ var result = "A";
+ var scrElem= document.createElement("script");
+ scrElem.textContent = "result+=\"B\";$(\"content\").innerHTML=\"--\";result+=\"C\";";
+ $("head").appendChild(scrElem);
+ result += "D";'></script>
+<script>result += "E"</script>
+<script>result += "F"</script>
+<script>is(result, "ABCDEF", "Wrong order of execution");</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug371576-4.html b/dom/base/test/test_bug371576-4.html
new file mode 100644
index 0000000000..8fbd81fe51
--- /dev/null
+++ b/dom/base/test/test_bug371576-4.html
@@ -0,0 +1,21 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=371576
+-->
+<head>
+ <title>Test2 for Bug 371576</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script>
+
+var _bShouldbeThere = false;
+var oScript = document.createElement('script');
+oScript.innerHTML = '_bShouldbeThere = true';
+document.getElementsByTagName('head')[0].appendChild(oScript);
+ok(_bShouldbeThere,"_bShouldbeThere is true, script has executed on time");
+
+</script>
+
+</head>
+</html>
diff --git a/dom/base/test/test_bug371576-5.html b/dom/base/test/test_bug371576-5.html
new file mode 100644
index 0000000000..842fa9e3c3
--- /dev/null
+++ b/dom/base/test/test_bug371576-5.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=371576
+-->
+<head id="head">
+ <title>Test for Bug 371576</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(
+ function doe(){
+ var x=document.createElement('script');
+ x.src='data:text/html,var scr=document.createElement("script");\
+ scr.innerHTML = "function doe3(){$(\'display\').innerHTML = \'You should see this text\';}";\
+ $("head").appendChild(scr);';
+ x.onload= function (){
+ doe3();
+ ok(true,"function doe3 is defined, and the body content has been replaced.");
+ is($("display").textContent, "You should see this text", "text set properly");
+ SimpleTest.finish();
+ };
+ $('head').appendChild(x);
+ }
+);
+</script>
+
+</head>
+<body>
+<p id="display">You shouldn't see this</p>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=371576">Mozilla Bug 371576</a>
+</body>
+</html>
diff --git a/dom/base/test/test_bug372086.html b/dom/base/test/test_bug372086.html
new file mode 100644
index 0000000000..e6ef6ee176
--- /dev/null
+++ b/dom/base/test/test_bug372086.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=372086
+-->
+<head>
+ <title>Test for Bug 372086</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=372086">Mozilla Bug 372086</a>
+<p id="display">
+ <div id="d" is="custom-div">abc</div>def
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 372086 **/
+
+customElements.define("custom-div", class extends HTMLDivElement {
+ constructor() {
+ super();
+ this.attachShadow({ mode: "open" });
+ this.shadowRoot.innerHTML = `ghi<slot></slot>jkl`;
+ }
+}, {
+ extends: "div",
+});
+
+function runTest() {
+ let range = document.createRange();
+
+ var c = $("d").firstChild;
+ var a = $("d").nextSibling;
+
+ range.setStart(c, 1);
+ range.setEnd(c, 3);
+ is(range.startContainer, c, "Unexpected start container");
+ is(range.startOffset, 1, "Unexpected start offset");
+ is(range.endContainer, c, "Unexpected end container");
+ is(range.endOffset, 3, "Unexpected end offset");
+ is(range.toString(), "bc", "Unexpected range serialization");
+
+ let shadow = d.shadowRoot.firstChild;
+ // Should collapse the range, because can't determine order
+ range.setEnd(shadow, 2);
+ is(range.startContainer, shadow,
+ "Unexpected collapsed start container");
+ is(range.startOffset, 2, "Unexpected collapsed start offset");
+ is(range.endContainer, shadow,
+ "Unexpected collapsed end container");
+ is(range.endOffset, 2, "Unexpected collapsed end offset");
+ is(range.toString(), "", "Unexpected collapsed range serialization");
+
+ range.setEnd(a, 2);
+ range.setStart(a, 0);
+ is(range.startContainer, a, "Unexpected start container after");
+ is(range.startOffset, 0, "Unexpected start offset after");
+ is(range.endContainer, a, "Unexpected end container after");
+ is(range.endOffset, 2, "Unexpected end offset after");
+ is(range.toString(), "de", "Unexpected range serialization after");
+
+ shadow = d.shadowRoot.lastChild;
+ // Collapses because one endpoint is anonymous from point of view of
+ // the other.
+ range.setStart(shadow, 1);
+ is(range.startContainer, shadow,
+ "Unexpected newly collapsed start container");
+ is(range.startOffset, 1, "Unexpected newly collapsed start offset");
+ is(range.endContainer, shadow,
+ "Unexpected newly collapsed end container");
+ is(range.endOffset, 1, "Unexpected newly collapsed end offset");
+ is(range.toString(), "", "Unexpected collapsed range serialization");
+
+ range.setEnd(shadow, 3);
+ is(range.startContainer, shadow,
+ "Unexpected shadow start container");
+ is(range.startOffset, 1, "Unexpected shadow start offset");
+ is(range.endContainer, shadow,
+ "Unexpected shadow end container");
+ is(range.endOffset, 3, "Unexpected shadow end offset");
+ is(range.toString(), "kl", "Unexpected shadow range serialization");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+addLoadEvent(SimpleTest.finish)
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug372964-2.html b/dom/base/test/test_bug372964-2.html
new file mode 100644
index 0000000000..f106965d6f
--- /dev/null
+++ b/dom/base/test/test_bug372964-2.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=372964
+-->
+<head>
+ <title>Test for Bug 372964</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=372964">Mozilla Bug 372964</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 372964 **/
+
+var eventCount = 0;
+
+function runTest() {
+ var ifr = document.getElementsByTagName("iframe")[0];
+ var xhr = new ifr.contentWindow.XMLHttpRequest();
+ xhr.addEventListener("foo", ifr.contentWindow.listener);
+ var event = ifr.contentDocument.createEvent("Events");
+ event.initEvent("foo", true, true);
+ xhr.dispatchEvent(event);
+ is(eventCount, 1, "Should have handled an event");
+ ifr.contentDocument.open();
+ ifr.contentDocument.close();
+ event = ifr.contentDocument.createEvent("Events");
+ event.initEvent("foo", true, true);
+ xhr.dispatchEvent(event);
+ is(eventCount, 2,
+ "Should have handled the event because open()/close() keep the active document");
+ ifr.onload = function() {
+ event = ifr.contentDocument.createEvent("Events");
+ event.initEvent("foo", true, true);
+ xhr.dispatchEvent(event);
+ is(eventCount, 2,
+ "Shouldn't have handled an event because the context has changed");
+ SimpleTest.finish();
+ };
+ ifr.contentWindow.location = "about:blank";
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+</script>
+</pre>
+<iframe srcdoc="<script>function listener() { ++parent.eventCount; } </script>"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug372964.html b/dom/base/test/test_bug372964.html
new file mode 100644
index 0000000000..c8f53850bc
--- /dev/null
+++ b/dom/base/test/test_bug372964.html
@@ -0,0 +1,144 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=372964
+-->
+<head>
+ <title>Test for Bug 372964</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=372964">Mozilla Bug 372964</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 372964 **/
+
+var expectedEventType = "";
+var shouldBeTrusted = false;
+var eventHandlerCallCount = 0;
+
+function eventHandler(evt) {
+ ++eventHandlerCallCount;
+ is(evt.type, expectedEventType, "Wrong event type");
+ is(evt.isTrusted, shouldBeTrusted, "Wrong .isTrusted");
+}
+
+function test(trusted, type, removeAddedListener, removeSetListener, allowUntrusted) {
+ if (trusted) {
+ var x1 = SpecialPowers.wrap(new XMLHttpRequest());
+ } else {
+ x1 = new XMLHttpRequest();
+ }
+
+ var handlerCount = 0;
+ if (trusted || allowUntrusted || allowUntrusted == undefined) {
+ ++handlerCount;
+ }
+
+ if (allowUntrusted == undefined) {
+ // Test .addEventListener with 3 parameters.
+ x1.addEventListener(type, eventHandler);
+ } else {
+ // Test .addEventListener with 4 parameters.
+ x1.addEventListener(type, eventHandler, false, allowUntrusted);
+ }
+
+ if (("on" + type) in x1) {
+ ++handlerCount;
+ x1["on" + type] = eventHandler;
+ }
+
+ if (removeAddedListener) {
+ x1.removeEventListener(type, eventHandler);
+ if (trusted || allowUntrusted || allowUntrusted == undefined) {
+ --handlerCount;
+ }
+ }
+
+ if (removeSetListener) {
+ if (("on" + type) in x1) {
+ --handlerCount;
+ x1["on" + type] = null;
+ }
+ }
+
+ var e1 = document.createEvent("Events");
+ e1.initEvent(type, true, true);
+ expectedEventType = type;
+ shouldBeTrusted = trusted;
+ var ecc = eventHandlerCallCount;
+ x1.dispatchEvent(e1);
+ is(eventHandlerCallCount, ecc + handlerCount,
+ "Wrong number event handler calls. (1)");
+
+ e1 = document.createEvent("Events");
+ e1.initEvent(type, true, true);
+ expectedEventType = type;
+ // Set trusted since open() may cause events to be sent.
+ shouldBeTrusted = true;
+ x1.open("GET", window.location);
+ x1.abort(); // This should not remove event listeners.
+ ecc = eventHandlerCallCount;
+ shouldBeTrusted = trusted;
+ x1.dispatchEvent(e1);
+ is(eventHandlerCallCount, ecc + handlerCount,
+ "Wrong number event handler calls. (2)");
+
+ e1 = document.createEvent("Events");
+ e1.initEvent(type, true, true);
+ expectedEventType = type;
+ // Set trusted since open()/send() may cause events to be sent.
+ shouldBeTrusted = true;
+ x1.open("GET", window.location);
+ x1.send("");
+ x1.abort(); // This should not remove event listeners!
+ ecc = eventHandlerCallCount;
+ shouldBeTrusted = trusted;
+ x1.dispatchEvent(e1);
+ is(eventHandlerCallCount, ecc + handlerCount,
+ "Wrong number event handler calls. (3)");
+}
+
+var events =
+ ["load", "error", "progress", "readystatechange", "foo"];
+
+do {
+ var e = events.shift();
+ test(false, e, false, false);
+ test(false, e, false, true);
+ test(false, e, true, false);
+ test(false, e, true, true);
+ test(true, e, false, false);
+ test(true, e, false, true);
+ test(true, e, true, false);
+ test(true, e, true, true);
+
+ test(false, e, false, false, false);
+ test(false, e, false, false, true);
+ test(false, e, false, true, false);
+ test(false, e, false, true, true);
+ test(false, e, true, false, false);
+ test(false, e, true, false, true);
+ test(false, e, true, true, false);
+ test(false, e, true, true, true);
+ test(true, e, false, false, false);
+ test(true, e, false, false, true);
+ test(true, e, false, true, false);
+ test(true, e, false, true, true);
+ test(true, e, true, false, false);
+ test(true, e, true, false, true);
+ test(true, e, true, true, false);
+ test(true, e, true, true, true);
+} while(events.length);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug373181.xhtml b/dom/base/test/test_bug373181.xhtml
new file mode 100644
index 0000000000..ed046e96c3
--- /dev/null
+++ b/dom/base/test/test_bug373181.xhtml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>Testcase for bug 373181</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"/>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/x-javascript">
+ function onLoadFired()
+ {
+ ok(true, "Body onload event should fire");
+ SimpleTest.finish();
+ }
+ SimpleTest.waitForExplicitFinish();
+ </script>
+ </head>
+ <body onload="onLoadFired();"/>
+</html>
diff --git a/dom/base/test/test_bug375314-2.html b/dom/base/test/test_bug375314-2.html
new file mode 100644
index 0000000000..89fa2aad67
--- /dev/null
+++ b/dom/base/test/test_bug375314-2.html
@@ -0,0 +1,151 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=375314
+-->
+<head>
+ <title>Test for Bug 375314</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=375314">Mozilla Bug 375314</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 375314 **/
+
+var lastContentType = -1;
+const testURL = window.location.href + "/this/is/the/test/url";
+
+function createChromeScript() {
+ /* eslint-env mozilla/chrome-script */
+ var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(
+ Ci.nsICategoryManager
+ );
+
+ const POLICYNAME = "@mozilla.org/testpolicy;1";
+ const POLICYID = Components.ID("{6cc95ef3-40e1-4d59-87f0-86f100373227}");
+
+ var policy = {
+ // nsISupports implementation
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIFactory",
+ "nsIContentPolicy",
+ ]),
+
+ // nsIFactory implementation
+ createInstance(iid) {
+ return this.QueryInterface(iid);
+ },
+
+ // nsIContentPolicy implementation
+ shouldLoad(contentLocation, loadInfo, mimeTypeGuess) {
+ if (contentLocation.asciiSpec === "http://mochi.test:8888/tests/dom/base/test/test_bug375314-2.html/this/is/the/test/url") {
+ sendAsyncMessage("loadBlocked", { policyType: loadInfo.externalContentPolicyType});
+ return Ci.nsIContentPolicy.REJECT_REQUEST;
+ }
+ return Ci.nsIContentPolicy.ACCEPT;
+ },
+
+ shouldProcess(contentLocation, loadInfo, mimeTypeGuess) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+ };
+
+ // Register content policy
+ var componentManager = Components.manager.QueryInterface(
+ Ci.nsIComponentRegistrar
+ );
+
+ componentManager.registerFactory(
+ POLICYID,
+ "Test content policy",
+ POLICYNAME,
+ policy
+ );
+ categoryManager.addCategoryEntry(
+ "content-policy",
+ POLICYNAME,
+ POLICYNAME,
+ false,
+ true
+ );
+
+ addMessageListener("shutdown", _ => {
+ categoryManager.deleteCategoryEntry(
+ "content-policy",
+ POLICYNAME,
+ false
+ );
+ componentManager.unregisterFactory(POLICYID, policy);
+ });
+
+ // Adding a new category dispatches an event to update
+ // caches, so we need to also dispatch an event to make
+ // sure we don't start the load until after that happens.
+ Services.tm.dispatchToMainThread(() => {
+ sendAsyncMessage("setupComplete");
+ });
+}
+
+// Request creating functions
+
+function requestDocument() {
+ // GeckoView shows an error page for CSP errors, which breaks this test, so just skip in that case.
+ try {
+ if (!SpecialPowers.Cc["@mozilla.org/android/bridge;1"].getService(SpecialPowers.Ci.nsIAndroidBridge).isFennec) {
+ return false;
+ }
+ } catch (e){}
+
+ top.location.href = testURL;
+ return true;
+}
+
+function requestSubdocument() {
+ var content = $("content");
+
+ var frame = document.createElement("iframe");
+ frame.setAttribute("src", testURL);
+ content.appendChild(frame);
+}
+
+function requestObject() {
+ var content = $("content");
+
+ var object = document.createElement("embed");
+ object.setAttribute("src", testURL);
+ content.appendChild(object);
+}
+
+add_task(async function() {
+ let chromeScript = SpecialPowers.loadChromeScript(createChromeScript);
+ await chromeScript.promiseOneMessage("setupComplete");
+
+ if (requestDocument()) {
+ let result = await chromeScript.promiseOneMessage("loadBlocked");
+ is(result.policyType, SpecialPowers.Ci.nsIContentPolicy.TYPE_DOCUMENT, "Content policies triggered for TYPE_DOCUMENT");
+ }
+
+ requestSubdocument();
+ result = await chromeScript.promiseOneMessage("loadBlocked");
+ is(result.policyType, SpecialPowers.Ci.nsIContentPolicy.TYPE_SUBDOCUMENT, "Content policies triggered for TYPE_SUBDOCUMENT");
+
+ requestObject();
+ result = await chromeScript.promiseOneMessage("loadBlocked");
+ is(result.policyType, SpecialPowers.Ci.nsIContentPolicy.TYPE_OBJECT, "Content policies triggered for TYPE_OBJECT");
+
+ chromeScript.sendAsyncMessage("shutdown");
+ chromeScript.destroy();
+});
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug375314.html b/dom/base/test/test_bug375314.html
new file mode 100644
index 0000000000..c7c69a8576
--- /dev/null
+++ b/dom/base/test/test_bug375314.html
@@ -0,0 +1,160 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=375314
+-->
+<head>
+ <title>Test for Bug 375314</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=375314">Mozilla Bug 375314</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 375314 **/
+
+var lastContentType = -1;
+const testURL = window.location.href + "/this/is/the/test/url";
+const Cc = SpecialPowers.Cc;
+const Ci = SpecialPowers.Ci;
+var { AppConstants } = SpecialPowers.ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+);
+
+// Content policy / factory implementation for the test
+var policyID = SpecialPowers.wrap(SpecialPowers.Components).ID("{b80e19d0-878f-d41b-2654-194714a4115c}");
+var policyName = "@mozilla.org/testpolicy;1";
+var policy = {
+ // nsISupports implementation
+ QueryInterface(iid) {
+
+ iid = SpecialPowers.wrap(iid);
+ if (iid.equals(Ci.nsISupports) ||
+ iid.equals(Ci.nsIFactory) ||
+ iid.equals(Ci.nsIContentPolicy))
+ return this;
+
+ throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
+ },
+
+ // nsIFactory implementation
+ createInstance(iid) {
+ return this.QueryInterface(iid);
+ },
+
+ // nsIContentPolicy implementation
+ shouldLoad(contentLocation, loadInfo, mimeTypeGuess) {
+ let contentType = loadInfo.externalContentPolicyType;
+ // Remember last content type seen for the test url
+ if (SpecialPowers.wrap(contentLocation).spec == testURL) {
+ lastContentType = contentType;
+ return Ci.nsIContentPolicy.REJECT_REQUEST;
+ }
+
+ return Ci.nsIContentPolicy.ACCEPT;
+ },
+
+ shouldProcess(contentLocation, loadInfo, mimeTypeGuess) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+}
+policy = SpecialPowers.wrapCallbackObject(policy);
+
+// Register content policy
+var componentManager = SpecialPowers.wrap(SpecialPowers.Components).manager
+ .QueryInterface(Ci.nsIComponentRegistrar);
+
+componentManager.registerFactory(policyID, "Test content policy", policyName, policy);
+
+var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
+categoryManager.addCategoryEntry("content-policy", policyName, policyName, false, true);
+
+// Try creating different request types
+var tests = ["SCRIPT", "IMAGE", "STYLESHEET", "XMLHTTPREQUEST"];
+var curTest = -1;
+var div;
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(runNextTest, 0);
+
+function runNextTest() {
+
+ if (curTest >= 0) {
+ var type = "TYPE_" + tests[curTest];
+ is(lastContentType, Ci.nsIContentPolicy[type], "Content policies triggered for " + type);
+ }
+
+ curTest++;
+ if (curTest < tests.length) {
+ var method = "request_" + tests[curTest].toLowerCase();
+ try {
+ window[method]();
+ } catch(e) {}
+ setTimeout(runNextTest, 0);
+ }
+ else {
+ // Unregister content policy
+ categoryManager.deleteCategoryEntry("content-policy", policyName, false);
+
+ setTimeout(function() {
+ // Component must be unregistered delayed, otherwise other content
+ // policy will not be removed from the category correctly
+ componentManager.unregisterFactory(policyID, policy);
+ }, 0);
+
+ SimpleTest.finish();
+ }
+}
+
+// Request creating functions
+
+function request_script() {
+ var content = $("content");
+
+ var script = document.createElement("script");
+ script.setAttribute("type", "text/javascript")
+ script.setAttribute("src", testURL)
+ content.appendChild(script);
+}
+
+function request_image() {
+ var content = $("content");
+
+ var image = new Image();
+ image.src = testURL;
+}
+
+function request_stylesheet() {
+ var content = $("content");
+
+ var stylesheet = document.createElement("link");
+ stylesheet.setAttribute("rel", "stylesheet");
+ stylesheet.setAttribute("type", "text/css");
+ stylesheet.setAttribute("href", testURL);
+ content.appendChild(stylesheet);
+}
+
+function request_object() {
+ var content = $("content");
+
+ var object = document.createElement("embed");
+ object.setAttribute("src", testURL);
+ content.appendChild(object);
+}
+
+function request_xmlhttprequest() {
+ var request = new XMLHttpRequest();
+ request.open("GET", testURL, false);
+ request.send(null);
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug378969.html b/dom/base/test/test_bug378969.html
new file mode 100644
index 0000000000..58d859d1b7
--- /dev/null
+++ b/dom/base/test/test_bug378969.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=378969
+-->
+<head>
+ <title>Test for Bug 378969</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=378969">Mozilla Bug 378969</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 378969 **/
+
+function do_test()
+{
+ var XHTMLDocString = '<html xmlns="http://www.w3.org/1999/xhtml">';
+ XHTMLDocString += '<body><input/>input</body></html>';
+
+ var doc = new DOMParser().parseFromString(XHTMLDocString, "application/xml");
+
+ var body = doc.getElementsByTagName("body")[0];
+ var filter = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT;
+ var walker = doc.createTreeWalker(body, filter, null);
+ walker.currentNode = body.firstChild;
+ walker.nextNode();
+
+ ok("A" == "A", "A is A");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(do_test);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug380418.html b/dom/base/test/test_bug380418.html
new file mode 100644
index 0000000000..45b6f21d99
--- /dev/null
+++ b/dom/base/test/test_bug380418.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=380418 -->
+<head>
+ <title>Test for Bug 380418</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=380418">Mozilla Bug 380418</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ var request = new XMLHttpRequest();
+ request.open("GET", window.location.href, false);
+ request.send(null);
+
+ // Try reading headers in unprivileged context
+ is(request.getResponseHeader("Set-Cookie"), null, "Reading Set-Cookie response header in unprivileged context");
+ is(request.getResponseHeader("Set-Cookie2"), null, "Reading Set-Cookie2 response header in unprivileged context");
+ is(request.getResponseHeader("X-Dummy"), "test", "Reading X-Dummy response header in unprivileged context");
+
+ ok(!/\bSet-Cookie:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie in all response headers in unprivileged context");
+ ok(!/\bSet-Cookie2:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie2 in all response headers in unprivileged context");
+ ok(/\bX-Dummy:/i.test(request.getAllResponseHeaders()), "Looking for X-Dummy in all response headers in unprivileged context");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug380418.html^headers^ b/dom/base/test/test_bug380418.html^headers^
new file mode 100644
index 0000000000..5f8d4969c0
--- /dev/null
+++ b/dom/base/test/test_bug380418.html^headers^
@@ -0,0 +1,4 @@
+Set-Cookie: test
+Set-Cookie2: test2
+X-Dummy: test
+Cache-Control: max-age=0
diff --git a/dom/base/test/test_bug382113.html b/dom/base/test/test_bug382113.html
new file mode 100644
index 0000000000..faf0deef25
--- /dev/null
+++ b/dom/base/test/test_bug382113.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=382113
+-->
+<head>
+ <title>Test for Bug 382113</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script class="testbody" type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+ var childGotOnload = false;
+ var objectGotOnload = false;
+
+ /** Test for Bug 100533 **/
+ function checkEvents() {
+ is(childGotOnload, true, "Child got load event");
+ is(objectGotOnload, true, "Object got load event");
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body onload="checkEvents()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=382113">Mozilla Bug 382113</a>
+<p id="display"></p>
+<div id="content">
+ <object type="text/html" data="bug382113_object.html"
+ onload="objectGotOnload = true;"></object>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug382871.html b/dom/base/test/test_bug382871.html
new file mode 100644
index 0000000000..1414954060
--- /dev/null
+++ b/dom/base/test/test_bug382871.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=382871
+-->
+<head>
+ <title>Test for Bug 382871</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=382871">Mozilla Bug 382871</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 382871 **/
+
+function loadHandler(evt) {
+ ok("randomProperty" in evt.target);
+ ok("randomProperty" in evt.target.upload);
+ SimpleTest.finish();
+}
+
+function runTest() {
+ var xhr = new XMLHttpRequest();
+ xhr.onload = loadHandler;
+ xhr.randomProperty = true;
+ xhr.upload.randomProperty = true;
+ xhr.open("GET", "test_bug382871.html");
+ xhr.send();
+ xhr = null;
+ SpecialPowers.gc();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug384003.xhtml b/dom/base/test/test_bug384003.xhtml
new file mode 100644
index 0000000000..6d1a4f5898
--- /dev/null
+++ b/dom/base/test/test_bug384003.xhtml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml" attr="value">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=384003
+-->
+<head>
+ <title>Test for Bug 384003</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=384003">Mozilla Bug 384003</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test" xmlns:foo="http://www.foo.org"><foo:foo/>
+<script type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 384003 **/
+
+
+function resolverTest(expr, resolver, result, extype) {
+ if (!extype) {
+ extype = 0;
+ }
+ try {
+ is(document.evaluate(expr, document, resolver,
+ XPathResult.FIRST_ORDERED_NODE_TYPE, null).
+ singleNodeValue,
+ result,
+ "Wrong XPathResult");
+ if (extype) {
+ ok(false, "Should have got an exception!");
+ }
+ } catch(ex) {
+ is(ex.name, extype, "Wrong exception");
+ }
+}
+
+// Expression should return document element.
+// Document resolver
+resolverTest("*", document, document.documentElement);
+// Element resolver
+resolverTest("*", document.documentElement, document.documentElement);
+// Attribute resolver
+resolverTest("*", document.documentElement.getAttributeNode("attr"),
+ document.documentElement);
+// Text node resolver
+resolverTest("*", document.documentElement.firstChild,
+ document.documentElement);
+// Comment node resolver
+resolverTest("*", document.documentElement.firstChild.nextSibling,
+ document.documentElement);
+
+// Expression should return foo element, but because of the
+// resolver it may throw an exception.
+var foo = document.getElementById("test").firstChild;
+// Document resolver
+resolverTest("//foo:foo", document, foo, "NamespaceError");
+// Element resolver
+resolverTest("//foo:foo", document.documentElement, foo, "NamespaceError");
+// Attribute resolver
+resolverTest("//foo:foo", document.documentElement.getAttributeNode("attr"),
+ foo, "NamespaceError");
+// Text node resolver
+resolverTest("//foo:foo", document.documentElement.firstChild,
+ foo, "NamespaceError");
+// Comment node resolver
+resolverTest("//foo:foo", document.documentElement.firstChild.nextSibling,
+ foo, "NamespaceError");
+// Function resolver
+resolverTest("//foo:foo",
+ function(p) { return (p == "foo") ? "http://www.foo.org" : ""; },
+ foo);
+// Element resolver, which has definition for foo namespace
+resolverTest("//foo:foo", foo.parentNode, foo);
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug390219.html b/dom/base/test/test_bug390219.html
new file mode 100644
index 0000000000..630b2bdd85
--- /dev/null
+++ b/dom/base/test/test_bug390219.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=390219
+-->
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>Test for Bug 390219</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 class="testbody" type="text/javascript">
+/** Test for Bug 390219 **/
+
+SimpleTest.waitForExplicitFinish();
+xhr = new XMLHttpRequest();
+xhr.open("GET", "nonexistent_url", true);
+xhr.send(null);
+xhr.abort();
+xhr.open("GET", ".", true);
+xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ is(xhr.status, 200, "wrong status");
+ SimpleTest.finish();
+ }
+}
+xhr.send(null);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug390735.html b/dom/base/test/test_bug390735.html
new file mode 100644
index 0000000000..57c300b5eb
--- /dev/null
+++ b/dom/base/test/test_bug390735.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=390735
+-->
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>Test for Bug 390735</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 class="testbody" type="text/javascript">
+/** Test for Bug 390735 **/
+
+var contents = document.getElementsByTagName("head")[0].innerHTML;
+var expectedFind = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">";
+
+ok(contents.indexOf(expectedFind) > -1, "The meta tag element was not found");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug392318.html b/dom/base/test/test_bug392318.html
new file mode 100644
index 0000000000..112468f894
--- /dev/null
+++ b/dom/base/test/test_bug392318.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=392318
+-->
+<head>
+ <title>Test for Bug 392318</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script class="testbody" type="text/javascript">
+ /** Test for Bug 392318 **/
+
+ SimpleTest.waitForExplicitFinish();
+ var testRan = false;
+
+ function runTest() {
+ isnot($("t").offsetWidth, 0, "Unexpected offsetWidth");
+ testRan = true;
+ }
+
+ document.addEventListener("DOMContentLoaded", runTest);
+
+ addLoadEvent(function() {
+ is(testRan, true, "Onload firing too early");
+ });
+
+ addLoadEvent(SimpleTest.finish);
+ </script>
+ <!-- IMPORTANT: This sheet must come after the test that sets up the
+ DOMContentLoaded handler and before the <body> -->
+ <link rel="stylesheet" type="text/css" href="data:text/css;%20charset=utf-8,%23t%20%7B%0Awidth%3A%20200px%3B%0Aborder%3A%201px%20solid%20black%3B%0Aheight%3A%20100px%3B%0A%7D">
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=392318">Mozilla Bug 392318</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<div id="t"></div>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug392511.html b/dom/base/test/test_bug392511.html
new file mode 100644
index 0000000000..b97d83377f
--- /dev/null
+++ b/dom/base/test/test_bug392511.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=392511
+-->
+<head>
+ <title>Test for Bug 392511</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=392511">Mozilla Bug 392511</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id="t1"><span onclick="&quot;&amp;"></span></div>
+ <div id="t2"><span foo="&quot;&amp;"></span></div>
+ <div id="t3"><span onclick='&apos;&amp;'></span></div>
+ <div id="t4"><span foo='&apos;&amp;'></span></div>
+ <div id="t5"><span onclick='"&apos;&amp;'></span></div>
+ <div id="t6"><span foo='"&apos;&amp;'></span></div>
+ <div id="t7"><span onclick="'&quot;&amp;"></span></div>
+ <div id="t8"><span foo="'&quot;&amp;"></span></div>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 392511 **/
+
+var results = [
+ "\"&quot;&amp;\"",
+ "\"&quot;&amp;\"",
+ "\"'&amp;\"",
+ "\"'&amp;\"",
+ "\"&quot;'&amp;\"",
+ "\"&quot;'&amp;\"",
+ "\"'&quot;&amp;\"",
+ "\"'&quot;&amp;\""
+];
+
+for (var i = 1; i <= 8; ++i) {
+ var id = "t" + i;
+ var str = $(id).innerHTML;
+ var expect = "<span ";
+ expect += (i % 2) ? "onclick" : "foo";
+ expect += "=" + results[i-1] + "></span>";
+ is (str, expect, "Wrong string for test " + id);
+}
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug393968.html b/dom/base/test/test_bug393968.html
new file mode 100644
index 0000000000..760aeaab55
--- /dev/null
+++ b/dom/base/test/test_bug393968.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=393968
+-->
+<head>
+ <title>Test for Bug 393968</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=393968">Mozilla Bug 393968</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({set: [["dom.xhr.standard_content_type_normalization", true]]},
+function() {
+
+/** Test for Bug 393968 **/
+var req = new XMLHttpRequest();
+req.open("POST", window.location.href);
+req.setRequestHeader("Content-Type", "text/plain; charset=us-ascii; boundary=01234567890");
+req.send("Some text");
+
+is(SpecialPowers.wrap(req).channel
+ .QueryInterface(SpecialPowers.Ci.nsIHttpChannel)
+ .getRequestHeader("Content-Type"),
+ "text/plain;charset=UTF-8;boundary=01234567890",
+ "Headers should match");
+
+SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug395915.html b/dom/base/test/test_bug395915.html
new file mode 100644
index 0000000000..711a6fd6a3
--- /dev/null
+++ b/dom/base/test/test_bug395915.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html class="A b">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=395915
+-->
+<head>
+ <title>Test for Bug 395915</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=395915">Mozilla Bug 395915</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 395915 **/
+is(document.getElementsByClassName("a").length, 0,
+ "Class names are case-sensitive");
+is(document.getElementsByClassName("A").length, 1,
+ "Have one node of class A");
+is(document.getElementsByClassName("A")[0], document.documentElement,
+ "Root is class A");
+
+is(document.getElementsByClassName("a b").length, 0,
+ "Class names are case-sensitive two");
+is(document.getElementsByClassName("A B").length, 0,
+ "Class names are case-sensitive three");
+is(document.getElementsByClassName("a B").length, 0,
+ "Class names are case-sensitive four");
+is(document.getElementsByClassName("A b").length, 1,
+ "Have one node of class 'A b'");
+is(document.getElementsByClassName("A b")[0], document.documentElement,
+ "Root is class 'A b'");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug397234.html b/dom/base/test/test_bug397234.html
new file mode 100644
index 0000000000..50686ee388
--- /dev/null
+++ b/dom/base/test/test_bug397234.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=397234
+-->
+<head>
+ <title>Test for Bug 397234</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=397234">Mozilla Bug 397234</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({set: [["dom.xhr.standard_content_type_normalization", true]]},
+function() {
+
+/** Test for Bug 397234 **/
+var req = new XMLHttpRequest();
+req.open("POST", window.location.href);
+// Capitalization of charet param is on purpose!
+req.setRequestHeader("Content-Type", "text/plain; charset='uTf-8'");
+req.send("Some text");
+
+is(SpecialPowers.wrap(req).channel
+ .QueryInterface(SpecialPowers.Ci.nsIHttpChannel)
+ .getRequestHeader("Content-Type"),
+ "text/plain;charset=UTF-8",
+ "Headers should match");
+
+SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug398243.html b/dom/base/test/test_bug398243.html
new file mode 100644
index 0000000000..11328f66ed
--- /dev/null
+++ b/dom/base/test/test_bug398243.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=398243
+-->
+<head>
+ <title>Test for Bug 398243</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=398243">Mozilla Bug 398243</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+ <iframe id="testframe" src="http://mochi.test:8888/tests/dom/base/test/formReset.html"></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 398243 **/
+const enteredText1 = "New value for text input";
+const enteredText2 = "New value for texarea";
+SimpleTest.waitForExplicitFinish();
+
+function afterLoad() {
+ var iframeDoc = $("testframe").contentDocument;
+ /* change all the form controls */
+ iframeDoc.getElementById("checkbox1").checked = true;
+ iframeDoc.getElementById("checkbox2").checked = false;
+ iframeDoc.getElementById("textinput").value = enteredText1;
+ iframeDoc.getElementById("textarea").value = enteredText2;
+
+ /* Reload the page */
+ $("testframe").setAttribute("onload", "afterReload()");
+ iframeDoc.location.reload();
+}
+
+addLoadEvent(afterLoad);
+
+function afterReload() {
+ var iframeDoc = $("testframe").contentDocument;
+ is(iframeDoc.getElementById("checkbox1").checked, true,
+ "checkbox #1 state preserved");
+ is(iframeDoc.getElementById("checkbox2").checked, false,
+ "checkbox #2 state preserved");
+ is(iframeDoc.getElementById("textinput").value, enteredText1,
+ "text preserved in <input>");
+ is(iframeDoc.getElementById("textarea").value, enteredText2,
+ "text preserved in <textarea>");
+
+ SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug401662.html b/dom/base/test/test_bug401662.html
new file mode 100644
index 0000000000..76b910ce74
--- /dev/null
+++ b/dom/base/test/test_bug401662.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=401662
+-->
+<head>
+ <title>Test for Bug 401662</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=401662">Mozilla Bug 401662</a>
+<p id="display"><iframe id="testframe2"
+ srcdoc="<html><body>foo<style style='display:block'>bar{}</style></body></html>">
+ </iframe>
+</p>
+<div id="content" style="display: none">
+ <iframe id="testframe"
+ srcdoc="<html><body>foo<style>bar</style></body></html>">
+ </iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 401662 - don't serialize style elements in body into
+ plaintext**/
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+ const Cu = SpecialPowers.Cu;
+
+ var encoder = Cu.createDocumentEncoder("text/html");
+ var doc = $("testframe").contentDocument;
+ encoder.init(doc, "text/plain", encoder.OutputBodyOnly);
+ encoder.setCharset("UTF-8");
+ var out = encoder.encodeToString();
+ is(out, "foo", "style content serialized in plaintext?");
+
+ var encoder = Cu.createDocumentEncoder("text/html");
+ var doc = $("testframe2").contentDocument;
+ encoder.init(doc, "text/plain", encoder.OutputBodyOnly);
+ encoder.setCharset("UTF-8");
+ var out = encoder.encodeToString();
+ is(out.replace(/\r\n/g, "\n"), "foo\nbar{}", "visible style content NOT serialized in plaintext?");
+
+ SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug402150.html b/dom/base/test/test_bug402150.html
new file mode 100644
index 0000000000..eb3bf84a53
--- /dev/null
+++ b/dom/base/test/test_bug402150.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=402150
+-->
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>Test for Bug 402150</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 class="testbody" type="text/javascript">
+/** Test for Bug 402150 **/
+ok(true, "The document loaded properly");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug402150.html^headers^ b/dom/base/test/test_bug402150.html^headers^
new file mode 100644
index 0000000000..453e7e1f37
--- /dev/null
+++ b/dom/base/test/test_bug402150.html^headers^
@@ -0,0 +1 @@
+Last-Modified: Fri, 2 Nov 19107 00:00:01 GMT
diff --git a/dom/base/test/test_bug403841.html b/dom/base/test/test_bug403841.html
new file mode 100644
index 0000000000..469b31730f
--- /dev/null
+++ b/dom/base/test/test_bug403841.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=403841
+-->
+<head>
+ <title>Test for Bug 403841</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=403841">Mozilla Bug 403841</a>
+<span id="content">abc</p>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 403841 - Crash in nsContentUtils::CreateContextualFragment when passed a non-element node as context node **/
+ var t = document.getElementById("content").firstChild;
+ var r = document.createRange();
+ r.setStart(t,0);
+ r.setEnd(t,3);
+ // make sure this doesn't crash
+ var f = r.createContextualFragment("<span>");
+ ok(f.firstChild instanceof HTMLSpanElement, "created fragment ok");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug403852.html b/dom/base/test/test_bug403852.html
new file mode 100644
index 0000000000..fec41e9cc4
--- /dev/null
+++ b/dom/base/test/test_bug403852.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=403852
+-->
+ <title>Test for Bug 403852</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=403852">Mozilla Bug 403852</a>
+<p id="display">
+ <input id="fileList" type="file"></input>
+</p>
+<div id="content" style="display: none">
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var script = '';
+SpecialPowers.pushPrefEnv({ "set":
+ [["privacy.reduceTimerPrecision", false]]},
+ function() {
+ var url = SimpleTest.getTestFileURL("bug403852_fileOpener.js");
+ script = SpecialPowers.loadChromeScript(url);
+ script.addMessageListener("file.opened", onOpened);
+ script.sendAsyncMessage("file.open");
+});
+
+function onOpened(message) {
+ var fileList = document.getElementById('fileList');
+ SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
+
+ // Make sure the file is accessible with indexed notation
+ var domFile = fileList.files[0];
+
+ is(domFile.name, "prefs.js", "fileName should be prefs.js");
+
+ ok("lastModified" in domFile, "lastModified must be present");
+
+ var d = new Date(message.mtime);
+ is(d.getTime(), (new Date(domFile.lastModified)).getTime(), "lastModified should be the same");
+
+ var x = new Date();
+
+ // In our implementation of File object, lastModified is unknown only for new objects.
+ // Using canvas or input[type=file] elements, we 'often' have a valid lastModified values.
+ // For canvas we use memory files and the lastModified is now().
+ var f = new File([new Blob(['test'], {type: 'text/plain'})], "test-name");
+
+ var y = new Date(f.lastModified);
+ var z = new Date();
+
+ ok((x.getTime() <= y.getTime()) && (y.getTime() <= z.getTime()), "lastModified of file which does not have last modified date should be current time");
+
+ script.destroy();
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body> </html>
diff --git a/dom/base/test/test_bug403868.xml b/dom/base/test/test_bug403868.xml
new file mode 100644
index 0000000000..cb2ababff4
--- /dev/null
+++ b/dom/base/test/test_bug403868.xml
@@ -0,0 +1,85 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=403868
+-->
+<head>
+ <title>Test for Bug 403868</title>
+ <script type="text/javascript" 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=403868">Mozilla Bug 403868</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+/** Test for Bug 403868 **/
+function createSpan(id, insertionPoint) {
+ var s = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
+ s.id = id;
+ $("content").insertBefore(s, insertionPoint);
+ return s;
+}
+
+var s1a = createSpan("test1", null);
+is(document.getElementById("test1"), s1a,
+ "Only one span with id=test1 in the tree; should work!");
+
+var s2a = createSpan("test1", null);
+is(document.getElementById("test1"), s1a,
+ "Appending span with id=test1 doesn't change which one comes first");
+
+var s3a = createSpan("test1", s2a);
+is(document.getElementById("test1"), s1a,
+ "Inserting span with id=test1 not at the beginning; doesn't matter");
+
+var s4a = createSpan("test1", s1a);
+is(document.getElementById("test1"), s4a,
+ "Inserting span with id=test1 at the beginning changes which one is first");
+
+s4a.parentNode.removeChild(s4a);
+is(document.getElementById("test1"), s1a,
+ "First-created span with id=test1 is first again");
+
+s1a.parentNode.removeChild(s1a);
+is(document.getElementById("test1"), s3a,
+ "Third-created span with id=test1 is first now");
+
+// Start the id hashtable
+for (var i = 0; i < 256; ++i) {
+ document.getElementById("no-such-id-in-the-document" + i);
+}
+
+var s1b = createSpan("test2", null);
+is(document.getElementById("test2"), s1b,
+ "Only one span with id=test2 in the tree; should work!");
+
+var s2b = createSpan("test2", null);
+is(document.getElementById("test2"), s1b,
+ "Appending span with id=test2 doesn't change which one comes first");
+
+var s3b = createSpan("test2", s2b);
+is(document.getElementById("test2"), s1b,
+ "Inserting span with id=test2 not at the beginning; doesn't matter");
+
+var s4b = createSpan("test2", s1b);
+is(document.getElementById("test2"), s4b,
+ "Inserting span with id=test2 at the beginning changes which one is first");
+
+s4b.parentNode.removeChild(s4b);
+is(document.getElementById("test2"), s1b,
+ "First-created span with id=test2 is first again");
+
+s1b.parentNode.removeChild(s1b);
+is(document.getElementById("test2"), s3b,
+ "Third-created span with id=test2 is first now");
+]]>
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug405182.html b/dom/base/test/test_bug405182.html
new file mode 100644
index 0000000000..d48d003ad0
--- /dev/null
+++ b/dom/base/test/test_bug405182.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=405182
+-->
+<head>
+ <title>Test for Bug 405182</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=405182">Mozilla Bug 405182</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 405182 **/
+
+function do_test()
+{
+ var dE = document.documentElement;
+
+ document.addEventListener("DOMNodeRemoved", newScript);
+
+ document.removeChild(dE);
+
+ function newScript()
+ {
+ var ns = document.createElementNS("http://www.w3.org/1999/xhtml", "script");
+ var nt = document.createTextNode("42;");
+ ns.appendChild(nt);
+ dE.appendChild(ns);
+ ok(true, "Test is successful if we get here without crashing");
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(do_test);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug409380.html b/dom/base/test/test_bug409380.html
new file mode 100644
index 0000000000..ddc796b223
--- /dev/null
+++ b/dom/base/test/test_bug409380.html
@@ -0,0 +1,378 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=409380
+-->
+<head>
+ <title>Test for Bug 409380</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=409380">Mozilla Bug 409380</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 409380 **/
+
+// eslint-disable-next-line complexity
+function runRangeTest()
+{
+ // Bug 336381
+ // This is a case which can't be supported (at least not at the moment)
+ // because DOM Range requires that when the start boundary point is text node,
+ // it must be splitted. But in this case boundary point doesn't have parent,
+ // so splitting doesn't work.
+ var zz = document.getElementById("connectedDiv").firstChild;
+ zz.remove();
+ var range = document.createRange();
+ var hadException = false;
+ try {
+ range.setStart(zz, 0);
+ range.setEnd(zz, 0);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException ,
+ "It should be possible to select text node even if the node is not in DOM.");
+ hadException = false;
+ try {
+ range.insertNode(document.createTextNode('5'));
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException,
+ "It shouldn't be possible to insert text node to a detached range.");
+
+ // Bug 409380
+ var element = document.createElement('div');
+ var elementContent = "This is the element content";
+ element.innerHTML = elementContent;
+ range = element.ownerDocument.createRange();
+ hadException = false;
+ try {
+ range.selectNodeContents(element);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException,
+ "It should be possible to select node contents of a detached element.");
+ ok(range.toString() == elementContent, "Wrong range selection");
+
+ // range.selectNode can't succeed because selectNode sets boundary points
+ // to be parentNode, which in this testcase is null.
+ element = document.createElement('div');
+ range = element.ownerDocument.createRange();
+ hadException = false;
+ try {
+ range.selectNode(element);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "It shouldn't be possible to select a detached element.");
+
+ // Testing contextual fragment.
+ range = element.ownerDocument.createRange();
+ var cf = null;
+ var testContent = "<span>foo</span><span>bar</span>";
+ try {
+ range.selectNodeContents(element);
+ cf = range.createContextualFragment(testContent);
+ element.appendChild(cf);
+ } catch (ex) {
+ }
+ ok(cf, "Creating contextual fragment didn't succeed!");
+ ok(element.innerHTML == testContent, "Wrong innerHTML!");
+
+ element = document.createElement('div');
+ element.textContent = "foobar";
+ range = element.ownerDocument.createRange();
+ try {
+ range.selectNodeContents(element);
+ element.firstChild.insertData(3, " ");
+ } catch (ex) {
+ }
+ ok(range.toString() == "foo bar");
+
+ // Testing contextual fragment, but inserting element to document
+ // after creating range.
+ element = document.createElement('div');
+ range = element.ownerDocument.createRange();
+ document.body.appendChild(element);
+ cf = null;
+ testContent = "<span>foo</span><span>bar</span>";
+ try {
+ range.selectNodeContents(element);
+ cf = range.createContextualFragment(testContent);
+ element.appendChild(cf);
+ } catch (ex) {
+ }
+ ok(cf, "Creating contextual fragment didn't succeed!");
+ ok(element.innerHTML == testContent, "Wrong innerHTML!");
+
+ // Testing contextual fragment, but inserting element to document
+ // before creating range.
+ element = document.createElement('div');
+ document.body.appendChild(element);
+ range = element.ownerDocument.createRange();
+ cf = null;
+ testContent = "<span>foo</span><span>bar</span>";
+ try {
+ range.selectNodeContents(element);
+ cf = range.createContextualFragment(testContent);
+ element.appendChild(cf);
+ } catch (ex) {
+ }
+ ok(cf, "Creating contextual fragment didn't succeed!");
+ ok(element.innerHTML == testContent, "Wrong innerHTML!");
+
+ element = document.createElement('div');
+ var range2 = element.ownerDocument.createRange();
+ hadException = false;
+ try {
+ range2.selectNodeContents(element);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException,
+ "It should be possible to select node contents of a detached element.");
+
+ // Now the boundary points of range are in DOM, but boundary points of
+ // range2 aren't.
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.START_TO_START, range2);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.START_TO_END, range2);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.END_TO_START, range2);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.END_TO_END, range2);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.START_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.START_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.END_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.END_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ // range3 will be in document
+ element = document.createElement('div');
+ document.body.appendChild(element);
+ range3 = element.ownerDocument.createRange();
+ hadException = false;
+ try {
+ range3.selectNodeContents(element);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException,
+ "It should be possible to select node contents of a detached element.");
+
+ hadException = false;
+ try {
+ range3.compareBoundaryPoints(range.START_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range3.compareBoundaryPoints(range.START_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range3.compareBoundaryPoints(range.END_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range3.compareBoundaryPoints(range.END_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ // range4 won't be in document
+ element = document.createElement('div');
+ var range4 = element.ownerDocument.createRange();
+ hadException = false;
+ try {
+ range4.selectNodeContents(element);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException,
+ "It should be possible to select node contents of a detached element.");
+
+ hadException = false;
+ try {
+ range4.compareBoundaryPoints(range.START_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.START_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range4.compareBoundaryPoints(range.END_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ hadException = false;
+ try {
+ range4.compareBoundaryPoints(range.END_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(hadException, "Should have got an exception!");
+
+ // Compare range to itself.
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.START_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.START_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.END_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range.compareBoundaryPoints(range.END_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ // Attach startContainer of range2 to document.
+ ok(range2.startContainer == range2.endContainer, "Wrong container?");
+ document.body.appendChild(range2.startContainer);
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.START_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.START_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.END_TO_START, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ hadException = false;
+ try {
+ range2.compareBoundaryPoints(range.END_TO_END, range);
+ } catch (ex) {
+ hadException = true;
+ }
+ ok(!hadException, "Shouldn't have got an exception!");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runRangeTest);
+
+</script>
+</pre>
+<div id="connectedDiv">zz</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug410229.html b/dom/base/test/test_bug410229.html
new file mode 100644
index 0000000000..9e3815b094
--- /dev/null
+++ b/dom/base/test/test_bug410229.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=410229
+-->
+<head>
+ <title>Test for Bug 410229</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=410229">Mozilla Bug 410229</a>
+<p id="display"></p>
+
+<span id="s"><span id="inner">Hello</span>
+<div>My</div>
+Kitty</span>
+
+<br>
+<span id="s2">Hello<div>My</div><span id="inner2">Kitty</span></span>
+
+<br>
+<span id="s3"><div id="inner3block">My</div><span id="inner3">Kitty</span></span>
+
+<br>
+<span id="s4"><div id="inner4block">My</div></span>
+
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var s = document.getElementById("s");
+var inner = document.getElementById("inner");
+var rects = s.getClientRects();
+is(s.getBoundingClientRect().top, inner.getBoundingClientRect().top,
+ "'"+s.id+"' "+"IB-split span should start where its first line starts");
+is(s.getClientRects().length, 3,
+ "'"+s.id+"' "+"IB-split span should have three CSS boxes");
+ok(rects[0].left < rects[0].right && rects[0].top < rects[0].bottom,
+ "'"+s.id+"' "+"IB-split span should have a non-zero width first rect");
+ok(rects[1].left < rects[1].right && rects[1].top < rects[1].bottom,
+ "'"+s.id+"' "+"IB-split span should have a non-zero width second rect");
+ok(rects[2].left < rects[2].right && rects[2].top < rects[2].bottom,
+ "'"+s.id+"' "+"IB-split span should have a non-zero width second rect");
+is(s.getBoundingClientRect().top, rects[0].top,
+ "'"+s.id+"' "+"IB-split span should start where its first rect starts");
+is(s.getBoundingClientRect().bottom, rects[2].bottom,
+ "'"+s.id+"' "+"IB-split span should end where its last rect ends");
+
+s = document.getElementById("s2");
+inner = document.getElementById("inner2");
+rects = s.getClientRects();
+is(s.getBoundingClientRect().bottom, inner.getBoundingClientRect().bottom,
+ "'"+s.id+"' "+"IB-split span should end where its last line ends");
+is(s.getClientRects().length, 3,
+ "'"+s.id+"' "+"IB-split span should have three CSS boxes");
+is(s.getBoundingClientRect().bottom, rects[2].bottom,
+ "'"+s.id+"' "+"IB-split span should end where its last rect ends");
+
+s = document.getElementById("s3");
+inner = document.getElementById("inner3");
+var block = document.getElementById("inner3block");
+rects = s.getClientRects();
+is(s.getBoundingClientRect().top, block.getBoundingClientRect().top,
+ "'"+s.id+"' "+"IB-split span should start where its first line starts");
+is(s.getBoundingClientRect().bottom, inner.getBoundingClientRect().bottom,
+ "'"+s.id+"' "+"IB-split span should end where its last line ends");
+is(s.getClientRects().length, 3,
+ "'"+s.id+"' "+"IB-split span should have three CSS boxes");
+is(rects[0].left, rects[0].right,
+ "'"+s.id+"' "+"IB-split span should have a zero width first rect");
+is(s.getBoundingClientRect().top, rects[1].top,
+ "'"+s.id+"' "+"IB-split span should start where its second rect starts");
+
+s = document.getElementById("s4");
+block = document.getElementById("inner4block");
+rects = s.getClientRects();
+is(s.getBoundingClientRect().top, block.getBoundingClientRect().top,
+ "'"+s.id+"' "+"IB-split span should start where its first line starts");
+is(s.getBoundingClientRect().bottom, block.getBoundingClientRect().bottom,
+ "'"+s.id+"' "+"IB-split span should end where its last line ends");
+is(s.getClientRects().length, 3,
+ "'"+s.id+"' "+"IB-split span should have three CSS boxes");
+is(rects[0].left, rects[0].right,
+ "'"+s.id+"' "+"IB-split span should have a zero width first rect");
+is(s.getBoundingClientRect().bottom, rects[1].bottom,
+ "'"+s.id+"' "+"IB-split span should end where its block rect ends");
+/*
+ok(rects[2].left == rects[2].right,
+ "'"+s.id+"' "+"IB-split span should have a zero width last rect");
+*/
+
+/*
+alert("'"+s.id+"' bounding rect:\n"+
+ ' left='+s.getBoundingClientRect().left+' right='+s.getBoundingClientRect().right+' top='+s.getBoundingClientRect().top+' bottom='+s.getBoundingClientRect().bottom + '\nclient rects:\n' +
+ ' left='+rects[0].left+' right='+rects[0].right+' top='+rects[0].top+' bottom='+rects[0].bottom + '\n' +
+ ' left='+rects[1].left+' right='+rects[1].right+' top='+rects[1].top+' bottom='+rects[1].bottom + '\n' +
+ ' left='+rects[2].left+' right='+rects[2].right+' top='+rects[2].top+' bottom='+rects[2].bottom + '\n');
+*/
+
+</script>
+</pre>
+</body>
+
+</html>
diff --git a/dom/base/test/test_bug413974.html b/dom/base/test/test_bug413974.html
new file mode 100644
index 0000000000..d1b1ca0cc1
--- /dev/null
+++ b/dom/base/test/test_bug413974.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=413974
+-->
+<head>
+ <title>Test for Bug 413974</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=413974">Mozilla Bug 413974</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 413974 **/
+var req = new XMLHttpRequest();
+req.open("POST", window.location.href);
+req.setRequestHeader("Content-Type", "text/plain; boundary=01234567890");
+req.send("Some text");
+
+is(SpecialPowers.wrap(req).channel
+ .QueryInterface(SpecialPowers.Ci.nsIHttpChannel)
+ .getRequestHeader("Content-Type"),
+ "text/plain; boundary=01234567890",
+ "Charset should come before boundary");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug414190.html b/dom/base/test/test_bug414190.html
new file mode 100644
index 0000000000..813d35ae7d
--- /dev/null
+++ b/dom/base/test/test_bug414190.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=414190
+-->
+<head>
+ <title>Test for Bug 414190</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=414190">Mozilla Bug 414190</a>
+<p id="display"></p>
+
+<table id="table" border="0" cellspacing="0" cellpadding="0"
+ style="width:100px; border:10px solid silver;">
+ <tr><td id="cell" style="height:100px;"></td></tr>
+ <caption id="caption" style="caption-side:bottom; width:50px; height:70px; background:yellow;"></caption>
+</table>
+
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function isEqualRect(r1, r2, r1border, s) {
+ is(r1.left + r1border, r2.left, s + " (left)");
+ is(r1.right - r1border, r2.right, s + " (right)");
+ is(r1.top + r1border, r2.top, s + " (top)");
+ is(r1.bottom - r1border, r2.bottom, s + " (bottom)");
+}
+
+function runTest() {
+ var table = document.getElementById("table");
+ var cell = document.getElementById("cell");
+ var caption = document.getElementById("caption");
+ var tableRects = table.getClientRects();
+ var tableBoundingRect = table.getBoundingClientRect();
+ var cellBoundingRect = cell.getBoundingClientRect();
+ var captionBoundingRect = caption.getBoundingClientRect();
+
+ is(tableRects.length, 2, "Table should have rects for body and caption");
+ isEqualRect(tableRects[0], cellBoundingRect, 10,
+ "Table first rect should be cell rect");
+ isEqualRect(tableRects[1], captionBoundingRect, 0,
+ "Table second rect should be caption rect");
+ is(cellBoundingRect.right - cellBoundingRect.left, 80, "Cell incorrect width");
+ is(cellBoundingRect.bottom - cellBoundingRect.top, 100, "Cell incorrect height");
+ is(captionBoundingRect.right - captionBoundingRect.left, 50, "Caption incorrect width");
+ is(captionBoundingRect.bottom - captionBoundingRect.top, 70, "Caption incorrect height");
+ is(captionBoundingRect.top, cellBoundingRect.bottom + 10, "Discontiguous vertical geometry");
+
+ is(tableBoundingRect.top, cellBoundingRect.top - 10, "Table top error");
+ is(tableBoundingRect.left, cellBoundingRect.left - 10, "Table left error");
+ is(tableBoundingRect.bottom, captionBoundingRect.bottom, "Table bottom error");
+ is(tableBoundingRect.right, cellBoundingRect.right + 10, "Table right error");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(runTest);
+</script>
+</pre>
+</body>
+
+</html>
diff --git a/dom/base/test/test_bug415860.html b/dom/base/test/test_bug415860.html
new file mode 100644
index 0000000000..1c00ce8843
--- /dev/null
+++ b/dom/base/test/test_bug415860.html
@@ -0,0 +1,240 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=415860
+-->
+<head>
+ <title>Test for Bug 415860</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=415860">Mozilla Bug 415860</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="testdata"> </div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 415860 **/
+
+function tests() {
+ // #text node
+ n = document.getElementById('testdata').firstChild;
+ s = getSelection();
+
+ // Initial text..
+ n.textContent = "Hello!";
+
+ // select the second last character
+ r = document.createRange();
+ r.setStart(n, 4);
+ r.setEnd(n, 5);
+ s.addRange(r);
+
+ ok(s == "o", "Should have selected 'o'");
+ ok(r.toString() == "o", "Range should be 'o'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+
+ // Update the text
+ n.textContent = "Hello!";
+
+ ok(s == "", "Should have selected ''");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+
+ // select the last character
+ r = document.createRange();
+ r.setStart(n, 5);
+ r.setEnd(n, 6);
+ s.addRange(r);
+
+ ok(s == "!", "Should have selected '!'");
+ ok(r.toString() == "!", "Range should be '!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+
+ // Update the text
+ n.textContent = "Hello!";
+ ok(s == "", "Should have selected ''");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+
+ r = document.createRange();
+ r.setStart(n, 5);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "!", "Range should be '!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ r.setStart(n, 0);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "Hello!", "Range should be 'Hello!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.deleteData(0, 1);
+ ok(n.nodeValue == "ello!", "Node value should be 'ello!'");
+ ok(r.toString() == "ello!", "Range should be 'ello!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.deleteData(0, 4);
+ ok(n.nodeValue == "!", "Node value should be '!'");
+ ok(r.toString() == "!", "Range should be '!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 0);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "Hello!", "Range should be 'Hello!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.replaceData(0, 6, "hELLO?");
+ ok(n.nodeValue == "hELLO?", "Node value should be 'hELLO?'");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 1);
+ r.setEnd(n, 3);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "el", "Range should be 'el'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.replaceData(2, 6, "END");
+ ok(n.nodeValue == "HeEND", "Node value should be 'HeEND!'");
+ ok(r.toString() == "e", "Range should be 'e'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 1);
+ r.setEnd(n, 5);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "ello", "Range should be 'ello'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.replaceData(2, 1, "MID");
+ ok(n.nodeValue == "HeMIDlo!", "Node value should be 'HeMIDlo!'");
+ ok(r.toString() == "eMIDlo", "Range should be 'eMIDlo'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 0);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "Hello!", "Range should be 'Hello!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "hELLO?...";
+ ok(n.nodeValue == "hELLO?...", "Node value should be 'hELLO?...'");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 1);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "ello!", "Range should be 'ello!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 0);
+ r.setEnd(n, 5);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "Hello", "Range should be 'Hello'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "hELLO?...";
+ ok(n.nodeValue == "hELLO?...", "Node value should be 'hELLO?...'");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 0);
+ r.setEnd(n, 5);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "Hello", "Range should be 'Hello'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "...";
+ ok(n.nodeValue == "...", "Node value should be '...'");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 1);
+ r.setEnd(n, 5);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "ello", "Range should be 'ello'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "...";
+ ok(n.nodeValue == "...", "Node value should be '...'");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+
+ n.textContent = "$";
+ r.setStart(n, 0);
+ r.setEnd(n, 1);
+ ok(n.nodeValue == "$", "Node value should be $'");
+ ok(r.toString() == "$", "Range should be '$'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "?";
+ ok(n.nodeValue == "?", "Node value should be '?'");
+ ok(r.toString() == "", "Range should be ''");
+ ok(r.collapsed == true, "Range should be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 3);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "lo!", "Range should be 'lo!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.replaceData(1, 4, "MID");
+ ok(n.nodeValue == "HMID!", "Node value should be 'HMID!'");
+ ok(r.toString() == "MID!", "Range should be 'MID!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "Hello!";
+ r.setStart(n, 3);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", "Node value should be 'Hello!'");
+ ok(r.toString() == "lo!", "Range should be 'lo!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.replaceData(1, 2, "MID");
+ ok(n.nodeValue == "HMIDlo!", "Node value should be 'HMIDlo!'");
+ ok(r.toString() == "MIDlo!", "Range should be 'MIDlo!'");
+ ok(r.collapsed == false, "Range shouldn't be collapsed");
+
+ n.textContent = "Hello!";
+ r = document.createRange();
+ r.setStart(n, 6);
+ r.setEnd(n, 6);
+ ok(n.nodeValue == "Hello!", " Node value should be 'Hello!'");
+ ok(r.toString() == "", " Range should be ''");
+ ok(r.startOffset == 6, "Start offset should be 6");
+ ok(r.endOffset == 6, "End offset should be 6");
+
+ n.textContent = "Hello!";
+ ok(n.nodeValue == "Hello!", " Node value should be 'Hello!'");
+ ok(r.toString() == "", " Range should be ''");
+ ok(r.startOffset == 0, "Start offset should be 0");
+ ok(r.endOffset == 0, "End offset should be 0");
+}
+
+tests();
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug416317-1.html b/dom/base/test/test_bug416317-1.html
new file mode 100644
index 0000000000..bc571ad4a2
--- /dev/null
+++ b/dom/base/test/test_bug416317-1.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=416317
+-->
+<head>
+ <title>Test for Bug 416317</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestLongerTimeout(3);
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=416317">Mozilla Bug 416317</a>
+<p id="display">
+ <iframe src="file_bug416317.xhtml#target"></iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 416317 **/
+// Subframe handles the test
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug416317-2.html b/dom/base/test/test_bug416317-2.html
new file mode 100644
index 0000000000..59d26fa70c
--- /dev/null
+++ b/dom/base/test/test_bug416317-2.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=416317
+-->
+<head>
+ <title>Test for Bug 416317</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=416317">Mozilla Bug 416317</a>
+<p id="display">
+ <iframe style="display: none" src="file_bug416317.xhtml#target"></iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 416317 **/
+SimpleTest.requestLongerTimeout(3);
+// Subframe handles the test
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug416383.html b/dom/base/test/test_bug416383.html
new file mode 100644
index 0000000000..8228d277f7
--- /dev/null
+++ b/dom/base/test/test_bug416383.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=416383
+-->
+<head>
+ <title>Test for Bug 416383</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=416383">Mozilla Bug 416383</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="test_parent"><div someattr="foo"></div></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 416383 **/
+
+function runTest() {
+ var testParent = document.getElementById("test_parent");
+ var attrs = testParent.firstChild.attributes;
+ ok(attrs != null, "Element should have attributes!");
+ var attr = testParent.firstChild.getAttributeNode("someattr");
+ ok(attr.value == "foo", "The value of the attribute should be 'foo'!");
+ testParent.firstChild.remove();
+ SpecialPowers.gc();
+ ok(true, "Browser should not crash!")
+
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+addLoadEvent(SimpleTest.finish);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug417255.html b/dom/base/test/test_bug417255.html
new file mode 100644
index 0000000000..0e7a137f0b
--- /dev/null
+++ b/dom/base/test/test_bug417255.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=417255
+-->
+<head>
+ <title>Test for Bug 417255</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style>
+ .spacer { display:inline-block; height:10px; }
+ </style>
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=417255">Mozilla Bug 417255</a>
+<div id="display" style="width:800px"></div>
+
+<div><span id="s1" style="border:2px dotted red;"><span class="spacer" style="width:100px"></span>
+<div style="width:500px; height:100px; background:yellow;"></div>
+<span class="spacer" style="width:200px"></span></span></div>
+
+<div><span id="s2" style="border:2px dotted red;"><span class="spacer" style="width:100px"></span>
+<div style="width:150px; height:100px; background:yellow;"></div>
+<span class="spacer" style="width:200px"></span></span></div>
+
+<!-- test nested spans around the IB split -->
+<div><span id="s3" style="border:2px dotted red;"><span><span class="spacer" style="width:100px"></span>
+<div style="width:500px; height:100px; background:yellow;"></div>
+<span class="spacer" style="width:200px"></span></span></span></div>
+
+<div id="content" style="display: none">
+
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function getWidth(box) {
+ return box.right - box.left;
+}
+
+function doTest(id, boundsWidth, w1, w2, w3) {
+ var s = document.getElementById(id);
+ is(s.offsetWidth, boundsWidth, "bad offsetWidth");
+ is(getWidth(s.getBoundingClientRect()), boundsWidth, "bad getBoundingClientRect width");
+ is(getWidth(s.getClientRects()[0]), w1, "bad getClientRects width");
+ is(getWidth(s.getClientRects()[1]), w2, "bad getClientRects width");
+ is(getWidth(s.getClientRects()[2]), w3, "bad getClientRects width");
+}
+
+doTest("s1", 500, 102, 500, 202);
+doTest("s2", 202, 102, 150, 202);
+doTest("s3", 500, 102, 500, 202);
+
+</script>
+</pre>
+</body>
+
+</html>
diff --git a/dom/base/test/test_bug417384.html b/dom/base/test/test_bug417384.html
new file mode 100644
index 0000000000..b99d96f155
--- /dev/null
+++ b/dom/base/test/test_bug417384.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=417384
+-->
+<head>
+ <title>Test for Bug 417384</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=417384">Mozilla Bug 417384</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 417384 **/
+
+var expectedSerialization = "about:blank document";
+function testSerializer() {
+ var doc = document.getElementById('test_iframe').contentDocument;
+ doc.body.textContent = expectedSerialization;
+ var head1 = doc.createElement("head");
+ doc.body.appendChild(head1);
+ var span = doc.createElement("span");
+ head1.appendChild(span);
+ span.appendChild(doc.createTextNode("before inner head\n"));
+ span.appendChild(doc.createElement("head"));
+ span.appendChild(doc.createTextNode("\nafter inner head"));
+
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("text/html");
+ encoder.init(doc, "text/plain", 0);
+ encoder.setCharset("UTF-8");
+ var out = encoder.encodeToString();
+ ok(out == expectedSerialization, "Wrong serialization!");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(testSerializer);
+addLoadEvent(SimpleTest.finish);
+
+</script>
+</pre>
+<iframe id="test_iframe" src="about:blank"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug418214.html b/dom/base/test/test_bug418214.html
new file mode 100644
index 0000000000..0c747a873f
--- /dev/null
+++ b/dom/base/test/test_bug418214.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=418214
+-->
+<head>
+ <title>Test for Bug 418214</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=418214">Mozilla Bug 418214</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var str = '<root xmlns:html="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:math="http://www.w3.org/1998/Math/MathML"><html:div id="d" style="border:: invalid"/><svg:svg id="s" style="border:: invalid"/><math:math id="m" style="border:: invalid"/></root>';
+
+/** Test for Bug 418214 **/
+var doc = (new DOMParser()).parseFromString(str, "text/xml");
+var d = doc.getElementById("d");
+var s = doc.getElementById("s");
+var m = doc.getElementById("m");
+
+is(d.getAttribute("style"), "border:: invalid",
+ "Shouldn't be parsing style on HTML in data documents");
+is(s.getAttribute("style"), "border:: invalid",
+ "Shouldn't be parsing style on SVG in data documents");
+is(m.getAttribute("style"), "border:: invalid",
+ "Shouldn't be parsing style on MathML in data documents");
+
+var d2 = d.cloneNode(true);
+var s2 = s.cloneNode(true);
+var m2 = m.cloneNode(true);
+
+is(d2.getAttribute("style"), "border:: invalid",
+ "Shouldn't be parsing style on HTML on clone");
+is(s2.getAttribute("style"), "border:: invalid",
+ "Shouldn't be parsing style on SVG on clone");
+is(m2.getAttribute("style"), "border:: invalid",
+ "Shouldn't be parsing style on MathML on clone");
+
+d2.style;
+s2.style;
+m2.style;
+
+is(d2.getAttribute("style"), "border:: invalid",
+ "Getting .style shouldn't affect style attribute on HTML");
+is(s2.getAttribute("style"), "border:: invalid",
+ "Getting .style shouldn't affect style attribute on SVG");
+is(m2.getAttribute("style"), "border:: invalid",
+ "Getting .style shouldn't affect style attribute on MathML");
+
+d2.style.color = "green";
+s2.style.color = "green";
+m2.style.color = "green";
+
+is(d2.getAttribute("style"), "color: green;",
+ "Adjusting .style should parse style on HTML");
+is(s2.getAttribute("style"), "color: green;",
+ "Adjusting .style should parse style on SVG");
+is(m2.getAttribute("style"), "color: green;",
+ "Adjusting .style should parse style on MathML");
+
+d = document.adoptNode(d);
+s = document.adoptNode(s);
+m = document.adoptNode(m);
+
+is(d.getAttribute("style"), "border:: invalid",
+ "Adopting should not parse style on HTML");
+is(s.getAttribute("style"), "border:: invalid",
+ "Adopting should not parse style on SVG");
+is(m.getAttribute("style"), "border:: invalid",
+ "Adopting should not parse style on MathML");
+
+$("display").appendChild(d);
+$("display").appendChild(s);
+$("display").appendChild(m);
+
+is(d.getAttribute("style"), "border:: invalid",
+ "Adopting should not parse style on HTML");
+is(s.getAttribute("style"), "border:: invalid",
+ "Adopting should not parse style on SVG");
+is(m.getAttribute("style"), "border:: invalid",
+ "Adopting should not parse style on MathML");
+
+d.style.color = "green";
+s.style.color = "green";
+m.style.color = "green";
+
+is(d.getAttribute("style"), "color: green;",
+ "Adjusting .style should parse style on HTML");
+is(s.getAttribute("style"), "color: green;",
+ "Adjusting .style should parse style on SVG");
+is(m.getAttribute("style"), "color: green;",
+ "Adjusting .style should parse style on MathML");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug418986-1.html b/dom/base/test/test_bug418986-1.html
new file mode 100644
index 0000000000..bbae1feced
--- /dev/null
+++ b/dom/base/test/test_bug418986-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=418986
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test 1/3 for Bug 418986 - Resist fingerprinting by preventing exposure of screen and system info</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="chrome/bug418986-1.js"></script>
+</head>
+<body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418986">Bug 418986</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test"></pre>
+ <script>
+ window.onload = function() {
+ test(true);
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug419132.html b/dom/base/test/test_bug419132.html
new file mode 100644
index 0000000000..c21e68afcf
--- /dev/null
+++ b/dom/base/test/test_bug419132.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=419132
+-->
+<head>
+ <title>Test for Bug 419132</title>
+ <script type="application/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=419132">Mozilla Bug 419132</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<iframe id="i"></iframe>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 419132 **/
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ var iframe = document.getElementById("i");
+ var loadCounts = 4;
+ iframe.addEventListener("load", function() {
+ if (--loadCounts == 0) {
+ ok(true, "This is a mochikit version of a crash test. To complete is to pass.");
+ SimpleTest.finish();
+ } else {
+ // Garbage collect after every other load
+ if ((loadCounts % 2) == 1) {
+ SpecialPowers.gc();
+ }
+ setTimeout(function() {
+ iframe.contentWindow.location.reload();
+ }, 0);
+ }
+ });
+ iframe.src = "bug419132.html";
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug419527.xhtml b/dom/base/test/test_bug419527.xhtml
new file mode 100644
index 0000000000..6b3644a0a0
--- /dev/null
+++ b/dom/base/test/test_bug419527.xhtml
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=419527
+-->
+<head>
+ <title>Test for Bug 419527</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<template id="template"><span>Foo</span></template>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=419527">Mozilla Bug 419527</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+/** Test for Bug 419527 **/
+customElements.define("custom-element", class extends HTMLElement {
+ constructor() {
+ super();
+ const template = document.getElementById("template");
+ const shadowRoot = this.attachShadow({mode: "open"})
+ .appendChild(template.content.cloneNode(true));
+ }
+ connectedCallback() {
+ var win = window;
+ var span = this.shadowRoot.children[0];
+ win.ok(span.textContent == "Foo", "Right span.");
+ win.ok(span.localName == "span", "Wrong anon node!");
+ var range = document.createRange();
+ range.selectNode(span.firstChild);
+ win.ok(range.startContainer == span, "Wrong start container!");
+ win.ok(range.endContainer == span, "Wrong end container!");
+ var newSubTree = win.newSubTree;
+ newSubTree.appendChild(this);
+ range.setStart(newSubTree.firstChild, 0);
+ win.ok(range.startContainer == newSubTree.firstChild,
+ "Range should have been collapsed to newSubTree.firstChild!");
+ win.ok(range.endContainer == newSubTree.firstChild,
+ "Range should have been collapsed to newSubTree.firstChild!");
+ SimpleTest.finish();
+ }
+});
+
+var d;
+
+function runRangeTest() {
+ window.newSubTree = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+ newSubTree.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "div"));
+
+ d = document.createElementNS("http://www.w3.org/1999/xhtml", "custom-element");
+ document.body.appendChild(d);
+}
+
+SimpleTest.waitForExplicitFinish();
+setTimeout(runRangeTest, 0);
+
+]]>
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug420609.xhtml b/dom/base/test/test_bug420609.xhtml
new file mode 100644
index 0000000000..64cbe3e320
--- /dev/null
+++ b/dom/base/test/test_bug420609.xhtml
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=420609
+-->
+<head>
+ <title>Test for Bug 420609</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=420609">Mozilla Bug 420609</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+&nbsp;&mdash;&sup1;&hellip;
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+/** Test for Bug 420609 **/
+ var request = new XMLHttpRequest();
+ request.open("GET", window.location.href, false);
+ request.send(null);
+
+ ok(request.responseXML && request.responseXML.documentElement.tagName == "html", "XMLHttpRequest should load XHTML document with entities");
+ is(document.getElementById("content").textContent, request.responseXML.getElementById("content").textContent, "Entities should be expanded in the document loaded by XMLHttpRequest");
+]]>
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug420700.html b/dom/base/test/test_bug420700.html
new file mode 100644
index 0000000000..cdab3fee8b
--- /dev/null
+++ b/dom/base/test/test_bug420700.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=420700
+-->
+<head>
+ <title>Test for Bug 420700</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=420700">Mozilla Bug 420700</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ var r = document.createRange();
+ r.selectNode(document.documentElement);
+
+ var df = r.createContextualFragment("<p>BAD</p>");
+
+ var display = document.getElementById("display");
+ display.innerHTML = "<p>GOOD</p>";
+
+ var p = display.firstChild;
+
+ is(p.textContent, "GOOD", "createContextualFragment tests");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug421602.html b/dom/base/test/test_bug421602.html
new file mode 100644
index 0000000000..b283d81fed
--- /dev/null
+++ b/dom/base/test/test_bug421602.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=421602
+-->
+<head>
+ <title>Test for Bug 421602</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=421602">Mozilla Bug 421602</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 421602 **/
+SimpleTest.waitForExplicitFinish();
+
+var img1loaded = false;
+var img1errored = false;
+
+// Our test image
+function loadTestImage() {
+ var img1 = new Image();
+ img1.onload = function() {
+ img1loaded = true;
+ finishTest();
+ }
+ img1.onerror = function() {
+ img1errored = true;
+ finishTest();
+ }
+ img1.src = window.location.href + "?image1=true";
+}
+loadTestImage();
+
+// Probably overkill to gc() more than once, but let's be safe
+SpecialPowers.gc(); SpecialPowers.gc(); SpecialPowers.gc();
+
+function finishTest() {
+ is(img1errored, true, "Image 1 should error");
+ is(img1loaded, false, "Image 1 should not load");
+ SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug422403-1.html b/dom/base/test/test_bug422403-1.html
new file mode 100644
index 0000000000..c3778cc075
--- /dev/null
+++ b/dom/base/test/test_bug422403-1.html
@@ -0,0 +1,204 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for XHTML serializer</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=422043">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<!-- IMPORTANT: This iframe needs to actually be displayed, so the serializer
+ sees the relevant styles for <pre> elements. -->
+<iframe id="testframe" src="file_xhtmlserializer_1.xhtml"></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+
+function loadFileContent(aFile, aCharset) {
+ //if(aAsIso == undefined) aAsIso = false;
+ if(aCharset == undefined)
+ aCharset = 'UTF-8';
+
+ var baseUri = SpecialPowers.Cc['@mozilla.org/network/standard-url-mutator;1']
+ .createInstance(SpecialPowers.Ci.nsIURIMutator)
+ .setSpec(window.location.href)
+ .finalize();
+
+ var ios = SpecialPowers.Cc['@mozilla.org/network/io-service;1']
+ .getService(SpecialPowers.Ci.nsIIOService);
+ var chann = ios.newChannel(aFile,
+ aCharset,
+ baseUri,
+ null, // aLoadingNode
+ SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal(),
+ null, // aTriggeringPrincipal
+ SpecialPowers.Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ SpecialPowers.Ci.nsIContentPolicy.TYPE_OTHER);
+
+ var cis = SpecialPowers.Ci.nsIConverterInputStream;
+
+ var inputStream = SpecialPowers.Cc["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(cis);
+ inputStream.init(chann.open(), aCharset, 1024, cis.DEFAULT_REPLACEMENT_CHARACTER);
+ var str = {}, content = '';
+ while (inputStream.readString(4096, str) != 0) {
+ content += str.value;
+ }
+ return content;
+}
+
+
+function testHtmlSerializer_1 () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("application/xhtml+xml");
+
+ var doc = SpecialPowers.wrap($("testframe")).contentDocument;
+ var out, expected;
+
+ // in the following tests, we must use the OutputLFLineBreak flag, to avoid
+ // to have the default line break of the platform in the result, so the test
+ // can pass on all platform
+
+ //------------ no flags
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_noflag.xhtml");
+ is(out, expected, "test no flags");
+
+ //------------- unsupported flags
+ // since the following flags are not supported, we should
+ // have a result like the one without flag
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputPreformatted);
+ out = encoder.encodeToString();
+ is(out, expected, "test OutputPreformatted");
+
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputFormatFlowed);
+ out = encoder.encodeToString();
+ is(out, expected, "test OutputFormatFlowed");
+
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputNoScriptContent);
+ out = encoder.encodeToString();
+ is(out, expected, "test OutputNoScriptContent");
+
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputNoFramesContent);
+ out = encoder.encodeToString();
+ is(out, expected, "test OutputNoFramesContent");
+
+
+ //------------ OutputWrap
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputWrap);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_wrap.xhtml");
+ is(out, expected, "test OutputWrap");
+
+ //------------ OutputFormatted
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputFormatted);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_format.xhtml");
+ is(out, expected, "test OutputFormatted");
+
+ //------------ OutputRaw
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputRaw);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_raw.xhtml");
+ is(out, expected, "test OutputRaw");
+
+ //------------ OutputBodyOnly
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputBodyOnly);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_bodyonly.xhtml");
+ is(out, expected, "test OutputBodyOnly");
+
+
+ //------------ OutputAbsoluteLinks
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputAbsoluteLinks);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_links.xhtml").trim('\n');
+ is(out, expected, "test OutputAbsoluteLinks");
+
+ //------------ OutputLFLineBreak
+ encoder.init(doc, "application/xhtml+xml",de.OutputLFLineBreak);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_linebreak.xhtml");
+ is(out, expected, "test OutputLFLineBreak");
+
+ //------------ OutputCRLineBreak
+ encoder.init(doc, "application/xhtml+xml",de.OutputCRLineBreak);
+ out = encoder.encodeToString();
+ expected = expected.replace(/\n/mg, "\r");
+ is(out, expected, "test OutputCRLineBreak");
+
+ //------------ OutputLFLineBreak + OutputCRLineBreak
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputCRLineBreak);
+ out = encoder.encodeToString();
+ expected = expected.replace(/\r/mg, "\r\n");
+ is(out, expected, "test OutputLFLineBreak + OutputCRLineBreak");
+
+ //------------ OutputNoFormattingInPre
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputNoFormattingInPre);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_noformatpre.xhtml");
+ is(out, expected, "test OutputNoFormattingInPre");
+
+ // ------------- nested body elements
+ var body2 = doc.createElement('body');
+ var p = doc.createElement('p');
+ p.appendChild(doc.createTextNode("this is an other body element"));
+ body2.appendChild(p);
+ var body = doc.getElementsByTagName('body')[0];
+ body.appendChild(body2);
+
+ is(doc.getElementsByTagName('body').length, 2); // to be sure we have two body elements
+
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_nested_body.xhtml");
+ is(out, expected, "test with two nested body elements");
+
+ // ------------- two body elements
+ body.parentNode.insertBefore(body2, body);
+
+ is(doc.getElementsByTagName('body').length, 2); // to be sure we have two body elements
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_sibling_body.xhtml");
+ is(out, expected, "test with two body elements");
+
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputBodyOnly);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_sibling_body_only_body.xhtml");
+ is(out, expected, "test with two body elements, and output body only");
+
+ // --------------- no body element
+ doc.documentElement.removeChild(body);
+ doc.documentElement.removeChild(body2);
+
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_1_no_body.xhtml");
+ is(out, expected, "test with no body element");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlSerializer_1);
+
+</script>
+</pre>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug422403-2.xhtml b/dom/base/test/test_bug422403-2.xhtml
new file mode 100644
index 0000000000..bff04c8f45
--- /dev/null
+++ b/dom/base/test/test_bug422403-2.xhtml
@@ -0,0 +1,296 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+-->
+<head>
+ <title>Test XHTML serializer with entities and selection</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=422043">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="testframe" src="file_xhtmlserializer_2.xhtml">
+ </iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//<![CDATA[
+
+function loadFileContent(aFile, aCharset) {
+ //if(aAsIso == undefined) aAsIso = false;
+ if(aCharset == undefined)
+ aCharset = 'UTF-8';
+
+ var baseUri = SpecialPowers.Cc['@mozilla.org/network/standard-url-mutator;1']
+ .createInstance(SpecialPowers.Ci.nsIURIMutator)
+ .setSpec(window.location.href)
+ .finalize();
+
+ var ios = SpecialPowers.Cc['@mozilla.org/network/io-service;1']
+ .getService(SpecialPowers.Ci.nsIIOService);
+ var chann = ios.newChannel(aFile,
+ aCharset,
+ baseUri,
+ null, // aLoadingNode
+ SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal(),
+ null, // aTriggeringPrincipal
+ SpecialPowers.Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ SpecialPowers.Ci.nsIContentPolicy.TYPE_OTHER);
+
+ var cis = SpecialPowers.Ci.nsIConverterInputStream;
+
+ var inputStream = SpecialPowers.Cc["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(cis);
+ inputStream.init(chann.open(), aCharset, 1024, cis.DEFAULT_REPLACEMENT_CHARACTER);
+ var str = {}, content = '';
+ while (inputStream.readString(4096, str) != 0) {
+ content += str.value;
+ }
+ return content;
+}
+
+
+function testHtmlSerializer_1 () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("application/xhtml+xml");
+
+ var doc = $("testframe").contentDocument;
+ var out, expected;
+
+ // in the following tests, we must use the OutputLFLineBreak flag, to avoid
+ // to have the default line break of the platform in the result, so the test
+ // can pass on all platform
+
+ //------------ OutputEncodeW3CEntities
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputEncodeW3CEntities);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_2_basic.xhtml");
+ is(out, expected, "test OutputEncodeW3CEntities");
+
+ //------------ OutputEncodeBasicEntities
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputEncodeBasicEntities);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_2_basic.xhtml");
+ is(out, expected, "test OutputEncodeBasicEntities");
+
+ //------------ OutputEncodeLatin1Entities
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputEncodeLatin1Entities);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_2_basic.xhtml");
+ is(out, expected, "test OutputEncodeLatin1Entities");
+
+ //------------ OutputEncodeHTMLEntities
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputEncodeHTMLEntities);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_xhtmlserializer_2_basic.xhtml");
+ is(out, expected, "test OutputEncodeHTMLEntities");
+
+ // tests on the serialization of selections
+
+ var node = document.getElementById('draggable');
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = 'This is a <em xmlns=\"http://www.w3.org/1999/xhtml\">draggable</em> bit of text.';
+ is(out, expected, "test selection");
+
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(null);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = 'This is a <em xmlns=\"http://www.w3.org/1999/xhtml\">draggable</em> bit of text.';
+ is(out, expected, "test container node");
+
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<div xmlns=\"http://www.w3.org/1999/xhtml\" id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>";
+ is(out, expected, "test node");
+
+ node = document.getElementById('aList');
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '\n <li xmlns=\"http://www.w3.org/1999/xhtml\">Lorem ipsum dolor</li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">sit amet, <strong>consectetuer</strong> </li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">adipiscing elit</li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">aptent taciti</li>\n';
+ is(out, expected, "test list selection");
+
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(null);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = '\n <li xmlns=\"http://www.w3.org/1999/xhtml\">Lorem ipsum dolor</li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">sit amet, <strong>consectetuer</strong> </li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">adipiscing elit</li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li xmlns=\"http://www.w3.org/1999/xhtml\">aptent taciti</li>\n';
+ is(out, expected, "test list container node");
+
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<ol xmlns=\"http://www.w3.org/1999/xhtml\" id=\"aList\">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>";
+ is(out, expected, "test list node");
+
+ var liList = node.getElementsByTagName("li");
+ var range = document.createRange();
+
+ // selection start at the first child of the ol, and end after the element ol
+ range.setStart(node, 1);
+ range.setEnd(node.parentNode, 2);
+ select.removeAllRanges();
+ select.addRange(range);
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol xmlns=\"http://www.w3.org/1999/xhtml\" id="aList"><li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the first child of the ol, and end after the element ol");
+
+ // selection start at the third child of the ol, and end after the element ol
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol xmlns=\"http://www.w3.org/1999/xhtml\" id="aList"><li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol");
+
+
+ // selection start at the third child of the ol, and end after the element ol + ol start at the value 5
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ node.setAttribute("start","5");
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol xmlns=\"http://www.w3.org/1999/xhtml\" id="aList" start="5"><li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol + ol start at the value 5");
+
+
+ // selection contains only some child of the ol
+ node.removeAttribute("start");
+ range.setStart(node, 3);
+ range.setEnd(node, 5);
+ encoder.init(document, "application/xhtml+xml", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li xmlns=\"http://www.w3.org/1999/xhtml\">sit amet, <strong>consectetuer</strong> </li>\n ';
+ is(out, expected, "test list selection with range: selection contains only some child of the ol");
+
+
+ // test on short attributes
+
+ node = document.getElementById('shortattr1');
+ encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<input xmlns="http://www.w3.org/1999/xhtml" id="shortattr1" checked="checked" value="" disabled="disabled" ismap="ismap" readonly="readonly" foo:checked="" xmlns:foo="http://mozilla.org/ns/any" foo:disabled="" />';
+ is(out, expected, "test short attr #1");
+
+ node = document.getElementById('shortattr2');
+ encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<ol xmlns="http://www.w3.org/1999/xhtml" id="shortattr2" compact="compact"><li></li></ol>';
+ is(out, expected, "test short attr #2");
+
+ node = document.getElementById('shortattr3');
+ encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<object xmlns="http://www.w3.org/1999/xhtml" id="shortattr3" declare="declare"></object>';
+ is(out, expected, "test short attr #3");
+
+ node = document.getElementById('shortattr4');
+ encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<script xmlns="http://www.w3.org/1999/xhtml" id="shortattr4" defer="defer"></script>';
+ is(out, expected, "test short attr #4");
+
+ node = document.getElementById('shortattr5');
+ encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<select xmlns="http://www.w3.org/1999/xhtml" id="shortattr5" multiple="multiple"><option selected="selected">aaa</option></select>';
+ is(out, expected, "test short attr #5");
+
+ node = document.getElementById('shortattr6');
+ encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<hr xmlns="http://www.w3.org/1999/xhtml" id="shortattr6" noshade="noshade" />';
+ is(out, expected, "test short attr #6");
+
+ node = document.getElementById('shortattr7');
+ encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<div xmlns="http://www.w3.org/1999/xhtml" id="shortattr7"><foo:bar xmlns:foo="http://mozilla.org/ns/any" checked="" value="" disabled="" ismap="" readonly=""/></div>';
+ is(out, expected, "test short attr #7");
+
+ // test on _moz and -moz attr
+ node = document.getElementById('mozattr');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<div id="mozattr" __moz_b="b"> lorem ipsum</div>';
+ is(out, expected, "test -moz/_moz attr");
+
+ node.setAttribute('_moz_c','barc');
+ node.setAttribute('_-moz_d','bard');
+ node.setAttribute('__moz_e','bare');
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<div id="mozattr" __moz_b="b" _-moz_d="bard" __moz_e="bare"> lorem ipsum</div>';
+ is(out, expected, "test -moz/_moz attr #2");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlSerializer_1);
+//]]>
+</script>
+</pre>
+<div style="display: none">
+
+<div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> bit of text.</div>
+
+</div>
+<div style="display: none">
+
+<ol id="aList">
+ <li>Lorem ipsum dolor</li>
+ <li>sit amet, <strong>consectetuer</strong> </li>
+ <li>adipiscing elit</li>
+ <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>
+ <li>aptent taciti</li>
+</ol>
+
+<!-- test for some short attr -->
+<div id="shortattr" xmlns:foo="http://mozilla.org/ns/any">
+ <input id="shortattr1" checked="" value="" disabled="" ismap="" readonly="" foo:checked="" foo:disabled=""/>
+ <ol id="shortattr2" compact=""><li></li></ol>
+ <object id="shortattr3" declare="" />
+ <script id="shortattr4" defer="" />
+ <select id="shortattr5" multiple=""><option selected="">aaa</option></select>
+ <hr id="shortattr6" noshade=""/>
+ <div id="shortattr7"><foo:bar checked="" value="" disabled="" ismap="" readonly="" /></div>
+ <div id="mozattr" _moz_a="a" __moz_b="b"> lorem ipsum</div>
+</div>
+
+</div>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug422537.html b/dom/base/test/test_bug422537.html
new file mode 100644
index 0000000000..f8cd03f111
--- /dev/null
+++ b/dom/base/test/test_bug422537.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=422537
+-->
+<head>
+ <title>Test for bug 422537</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=422537">Mozilla Bug 422537</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 422537 **/
+var isupports_string = SpecialPowers.Cc["@mozilla.org/supports-string;1"]
+ .createInstance(SpecialPowers.Ci.nsISupportsString);
+isupports_string.data = "foo";
+
+const url = "http://mochi.test:8888";
+var body = [
+ document,
+ "foo",
+ isupports_string
+];
+
+for (var i of body) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("POST", url, true);
+ if (i == isupports_string)
+ SpecialPowers.wrap(xhr).send(i);
+ else
+ xhr.send(i);
+ var chan = SpecialPowers.wrap(xhr).channel;
+ if (!SpecialPowers.call_Instanceof(chan, SpecialPowers.Ci.nsIUploadChannel))
+ throw "Must be an upload channel";
+ var stream = chan.uploadStream;
+ if (!stream || !SpecialPowers.call_Instanceof(stream, SpecialPowers.Ci.nsISeekableStream))
+ throw "Stream must be seekable";
+ // the following is a no-op, but should not throw an exception
+ stream.seek(SpecialPowers.Ci.nsISeekableStream.NS_SEEK_CUR, 0);
+}
+
+ok(true, "xhr is seekable");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug424212.html b/dom/base/test/test_bug424212.html
new file mode 100644
index 0000000000..4203794c01
--- /dev/null
+++ b/dom/base/test/test_bug424212.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=424212
+-->
+<head>
+ <title>Test for Bug 424212</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=424212">Mozilla Bug 424212</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 424212 **/
+var fired = false;
+var xhr = new XMLHttpRequest();
+xhr.open("GET", window.location.href + "?" + Math.random());
+xhr.send("");
+xhr.onreadystatechange = function () {
+ fired = true;
+ is(xhr.status, 0, "Unexpected status");
+}
+xhr.abort();
+is(fired, true, "No onreadystatechange handling?");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug424359-1.html b/dom/base/test/test_bug424359-1.html
new file mode 100644
index 0000000000..870b54438d
--- /dev/null
+++ b/dom/base/test/test_bug424359-1.html
@@ -0,0 +1,213 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for HTML serializer</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=424359">Mozilla Bug </a>
+<p id="display"></p>
+<!-- IMPORTANT: This iframe needs to actually be displayed, so the serializer
+ sees the relevant styles for <pre> elements. -->
+<iframe id="testframe" src="file_htmlserializer_1.html"></iframe>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+
+function loadFileContent(aFile, aCharset) {
+ //if(aAsIso == undefined) aAsIso = false;
+ if(aCharset == undefined)
+ aCharset = 'UTF-8';
+
+ var baseUri = SpecialPowers.Cc['@mozilla.org/network/standard-url-mutator;1']
+ .createInstance(SpecialPowers.Ci.nsIURIMutator)
+ .setSpec(window.location.href)
+ .finalize();
+
+ var ios = SpecialPowers.Cc['@mozilla.org/network/io-service;1']
+ .getService(SpecialPowers.Ci.nsIIOService);
+ var chann = ios.newChannel(aFile,
+ aCharset,
+ baseUri,
+ null, // aLoadingNode
+ SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal(),
+ null, // aTriggeringPrincipal
+ SpecialPowers.Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ SpecialPowers.Ci.nsIContentPolicy.TYPE_OTHER);
+
+ var cis = SpecialPowers.Ci.nsIConverterInputStream;
+
+ var inputStream = SpecialPowers.Cc["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(cis);
+ inputStream.init(chann.open(), aCharset, 1024, cis.DEFAULT_REPLACEMENT_CHARACTER);
+ var str = {}, content = '';
+ while (inputStream.readString(4096, str) != 0) {
+ content += str.value;
+ }
+ return content;
+}
+
+function isRoughly(actual, expected, message) {
+ return is(actual.replace("<!DOCTYPE HTML", "<!DOCTYPE html"),
+ expected,
+ message);
+}
+
+function testHtmlSerializer_1 () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder;
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("text/html");
+
+ var doc = $("testframe").contentDocument;
+ var out, expected;
+
+ // in the following tests, we must use the OutputLFLineBreak flag, to avoid
+ // to have the default line break of the platform in the result, so the test
+ // can pass on all platform
+
+ //------------ no flags
+ encoder.init(doc, "text/html", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_noflag.html");
+ isRoughly(out, expected, "test no flags");
+
+ //------------- unsupported flags
+ // since the following flags are not supported, we should
+ // have a result like the one without flag
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputPreformatted);
+ out = encoder.encodeToString();
+ isRoughly(out, expected, "test OutputPreformatted");
+
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputFormatFlowed);
+ out = encoder.encodeToString();
+ isRoughly(out, expected, "test OutputFormatFlowed");
+
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputNoScriptContent);
+ out = encoder.encodeToString();
+ isRoughly(out, expected, "test OutputNoScriptContent");
+
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputNoFramesContent);
+ out = encoder.encodeToString();
+ isRoughly(out, expected, "test OutputNoFramesContent");
+
+
+ //------------ OutputWrap
+ encoder.init(doc, "text/html", de.OutputLFLineBreak |de.OutputWrap);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_wrap.html");
+ isRoughly(out, expected, "test OutputWrap");
+
+ //------------ OutputFormatted
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputFormatted);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_format.html");
+ isRoughly(out, expected, "test OutputFormatted");
+
+ //------------ OutputRaw
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputRaw);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_raw.html");
+ isRoughly(out, expected, "test OutputRaw");
+
+ //------------ OutputBodyOnly
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputBodyOnly);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_bodyonly.html");
+ isRoughly(out, expected, "test OutputBodyOnly");
+
+
+
+ //------------ OutputAbsoluteLinks
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputAbsoluteLinks);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_links.html").trim('\n');
+ isRoughly(out, expected, "test OutputAbsoluteLinks");
+
+ //------------ OutputLFLineBreak
+ encoder.init(doc, "text/html",de.OutputLFLineBreak);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_linebreak.html");
+ isRoughly(out, expected, "test OutputLFLineBreak");
+
+ //------------ OutputCRLineBreak
+ encoder.init(doc, "text/html",de.OutputCRLineBreak);
+ out = encoder.encodeToString();
+ expected = expected.replace(/\n/mg, "\r");
+ isRoughly(out, expected, "test OutputCRLineBreak");
+
+ //------------ OutputLFLineBreak + OutputCRLineBreak
+ encoder.init(doc, "text/html",de.OutputLFLineBreak | de.OutputCRLineBreak);
+ out = encoder.encodeToString();
+ expected = expected.replace(/\r/mg, "\r\n");
+ isRoughly(out, expected, "test OutputLFLineBreak + OutputCRLineBreak");
+
+ //------------ OutputNoFormattingInPre
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputNoFormattingInPre);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_noformatpre.html");
+ isRoughly(out, expected, "test OutputNoFormattingInPre");
+
+ // ------------- nested body elements
+ var body2 = doc.createElement('body');
+ var p = doc.createElement('p');
+ p.appendChild(doc.createTextNode("this is an other body element"));
+ body2.appendChild(p);
+ var body = doc.getElementsByTagName('body')[0];
+ body.appendChild(body2);
+
+ is(doc.getElementsByTagName('body').length, 2); // to be sure we have two body elements
+
+ encoder.init(doc, "text/html", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_nested_body.html");
+ isRoughly(out, expected, "test with two nested body elements");
+
+ // ------------- two body elements
+ body.parentNode.insertBefore(body2, body);
+
+ is(doc.getElementsByTagName('body').length, 2); // to be sure we have two body elements
+ encoder.init(doc, "text/html", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_sibling_body.html");
+ isRoughly(out, expected, "test with two body elements");
+
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputBodyOnly);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_sibling_body_only_body.html");
+ isRoughly(out, expected, "test with two body elements, and output body only");
+
+ // --------------- no body element
+ doc.documentElement.removeChild(body);
+ doc.documentElement.removeChild(body2);
+
+ encoder.init(doc, "text/html", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_1_no_body.html");
+ isRoughly(out, expected, "test with no body element");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlSerializer_1);
+
+</script>
+</pre>
+<!--<h1>1</h1><h2>result</h2><textarea id="t1" cols="80" rows="20"></textarea>
+ <h2>expected</h2><textarea id="t1e" cols="80" rows="20"></textarea>-->
+
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug424359-2.html b/dom/base/test/test_bug424359-2.html
new file mode 100644
index 0000000000..b3ad1bfe5a
--- /dev/null
+++ b/dom/base/test/test_bug424359-2.html
@@ -0,0 +1,301 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test HTML serializer with entities</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=424359">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="testframe" src="file_htmlserializer_2.html">
+ </iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+
+function loadFileContent(aFile, aCharset) {
+ //if(aAsIso == undefined) aAsIso = false;
+ if(aCharset == undefined)
+ aCharset = 'UTF-8';
+
+ var baseUri = SpecialPowers.Cc['@mozilla.org/network/standard-url-mutator;1']
+ .createInstance(SpecialPowers.Ci.nsIURIMutator)
+ .setSpec(window.location.href)
+ .finalize();
+
+ var ios = SpecialPowers.Cc['@mozilla.org/network/io-service;1']
+ .getService(SpecialPowers.Ci.nsIIOService);
+ var chann = ios.newChannel(aFile,
+ aCharset,
+ baseUri,
+ null, // aLoadingNode
+ SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal(),
+ null, // aTriggeringPrincipal
+ SpecialPowers.Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ SpecialPowers.Ci.nsIContentPolicy.TYPE_OTHER);
+
+ var cis = SpecialPowers.Ci.nsIConverterInputStream;
+
+ var inputStream = SpecialPowers.Cc["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(cis);
+ inputStream.init(chann.open(), aCharset, 1024, cis.DEFAULT_REPLACEMENT_CHARACTER);
+ var str = {}, content = '';
+ while (inputStream.readString(4096, str) != 0) {
+ content += str.value;
+ }
+ return content;
+}
+
+function isRoughly(actual, expected, message) {
+ return is(actual.replace("<!DOCTYPE HTML", "<!DOCTYPE html"),
+ expected,
+ message);
+}
+
+function testHtmlSerializer_1 () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder;
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("text/html");
+
+ var doc = $("testframe").contentDocument;
+ var out, expected;
+
+ // in the following test, we must use the OutputLFLineBreak flag, to avoid
+ // to have the default line break of the platform in the result, so the test
+ // can pass on all platform
+
+ //------------ OutputEncodeBasicEntities
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputEncodeBasicEntities);
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_2_basic.html");
+ isRoughly(out, expected, "test OutputEncodeBasicEntities");
+
+ // tests on the serialization of selections
+
+ var node = document.getElementById('draggable');
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = 'This is a <em>draggable</em> bit of text.';
+ is(out, expected, "test selection");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(null);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = 'This is a <em>draggable</em> bit of text.';
+ is(out, expected, "test container node");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>";
+ is(out, expected, "test node");
+
+ node = document.getElementById('aList');
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n';
+ is(out, expected, "test list selection");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(null);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = '\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n';
+ is(out, expected, "test list container node");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<ol id=\"aList\">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>";
+ is(out, expected, "test list node");
+
+ var liList = node.getElementsByTagName("li");
+ var range = document.createRange();
+
+ // selection start at the first child of the ol, and end after the element ol
+ range.setStart(node, 1);
+ range.setEnd(node.parentNode, 2);
+ select.removeAllRanges();
+ select.addRange(range);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id="aList"><li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the first child of the ol, and end after the element ol");
+
+ // selection start at the third child of the ol, and end after the element ol
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id="aList"><li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol");
+
+
+ // selection start at the third child of the ol, and end after the element ol + ol start at the value 5
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ node.setAttribute("start","5");
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id="aList" start="5"><li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol + ol start at the value 5");
+
+
+ // selection contains only some child of the ol
+ node.removeAttribute("start");
+ range.setStart(node, 3);
+ range.setEnd(node, 5);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ is(out, expected, "test list selection with range: selection contains only some child of the ol");
+
+ // selection contains only some child of the ol + ol start at the value 5
+ node.setAttribute("start","5");
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ is(out, expected, "test list selection with range: selection contains only some child of the ol + ol start at the value 5");
+
+ // selection contains only some child of the ol + a value is set on the first li
+ node.removeAttribute("start");
+ liList[0].setAttribute("value","8");
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ is(out, expected, "test list selection with range: selection contains only some child of the ol + ol start at the value 5");
+
+
+
+ // test on short attributes
+ node = document.getElementById('shortattr1');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<input id="shortattr1" checked="checked" value="" disabled="disabled" ismap="ismap" readonly="readonly" foo="">';
+ is(out, expected, "test short attr #1");
+
+ node = document.getElementById('shortattr2');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<ol id="shortattr2" compact="compact"><li></li></ol>';
+ is(out, expected, "test short attr #2");
+
+ node = document.getElementById('shortattr3');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<object id="shortattr3" declare="declare"></object>';
+ is(out, expected, "test short attr #3");
+
+ node = document.getElementById('shortattr4');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<script id="shortattr4" defer="defer"></'+ 'script>';
+ is(out, expected, "test short attr #4");
+
+ node = document.getElementById('shortattr5');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<select id="shortattr5" multiple="multiple"><option selected="selected">aaa</option></select>';
+ is(out, expected, "test short attr #5");
+
+ node = document.getElementById('shortattr6');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<hr id="shortattr6" noshade="noshade">';
+ is(out, expected, "test short attr #6");
+
+ node = document.getElementById('shortattr7');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<div id="shortattr7"><foo checked="" value="" disabled="" ismap="" readonly=""></foo></div>';
+ is(out, expected, "test short attr #7");
+
+ // test on _moz and -moz attr
+ node = document.getElementById('mozattr');
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<div id="mozattr" __moz_b="b"> lorem ipsum</div>';
+ is(out, expected, "test -moz/_moz attr");
+
+ node.setAttribute('_moz_c','barc');
+ node.setAttribute('_-moz_d','bard');
+ node.setAttribute('__moz_e','bare');
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = '<div id="mozattr" __moz_b="b" _-moz_d="bard" __moz_e="bare"> lorem ipsum</div>';
+ is(out, expected, "test -moz/_moz attr #2");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlSerializer_1);
+
+</script>
+</pre>
+<div style="display: none">
+
+<div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> bit of text.</div>
+
+</div>
+<div style="display: none">
+
+<ol id="aList">
+ <li>Lorem ipsum dolor</li>
+ <li>sit amet, <strong>consectetuer</strong> </li>
+ <li>adipiscing elit</li>
+ <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>
+ <li>aptent taciti</li>
+</ol>
+
+
+<!-- test for some short attr -->
+<div id="shortattr">
+ <input id="shortattr1" checked="" value="" disabled="" ismap="" readonly="" foo="">
+ <ol id="shortattr2" compact=""><li></li></ol>
+ <object id="shortattr3" declare=""></object>
+ <script id="shortattr4" defer=""></script>
+ <select id="shortattr5" multiple=""><option selected="">aaa</option></select>
+ <hr noshade="" id="shortattr6">
+ <div id="shortattr7"><foo checked="" value="" disabled="" ismap="" readonly=""></div>
+ <div id="mozattr" _moz_a="a" __moz_b="b"> lorem ipsum</div>
+</div>
+
+
+
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug426308.html b/dom/base/test/test_bug426308.html
new file mode 100644
index 0000000000..6587a6f2f3
--- /dev/null
+++ b/dom/base/test/test_bug426308.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=426308
+-->
+<head>
+ <title>Test for Bug 426308</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=426308">Mozilla Bug 426308</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 426308 **/
+
+const SJS_URL = "http://example.org:80/tests/dom/base/test/bug426308-redirect.sjs";
+
+function startTest() {
+ var req = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+ req.open("GET", SJS_URL + "?" + window.location.href, false);
+ req.send(null);
+
+ is(req.status, 200, "Redirect did not happen");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], startTest);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug426646.html b/dom/base/test/test_bug426646.html
new file mode 100644
index 0000000000..d5a0a18c01
--- /dev/null
+++ b/dom/base/test/test_bug426646.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=426646
+-->
+<head>
+ <title>Test for Bug 426646</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=426646">Mozilla Bug 426646</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 426646 **/
+
+var testNumber = 0;
+var testCount = 2;
+
+function nextTest() {
+ if (++testNumber <= testCount) {
+ window.open("file_bug426646-" + testNumber + ".html", "", "width=100,height=100");
+ } else {
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(nextTest);
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug428847.html b/dom/base/test/test_bug428847.html
new file mode 100644
index 0000000000..e34eb183bf
--- /dev/null
+++ b/dom/base/test/test_bug428847.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=428847
+-->
+<head>
+ <title>Test for Bug 428847</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runtests();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=428847">Mozilla Bug 428847</a>
+<script class="testbody" type="text/javascript">
+var iframe1Loaded = false;
+var iframe2Loaded = false;
+
+function runtests()
+{
+ todo(iframe1Loaded, true,
+ "Iframe with cross-origin xslt stylesheet failed to load");
+ is(iframe2Loaded, false,
+ "Iframe with invalid xslt stylesheet URI didn't fail to load");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+<iframe src="file_bug428847-1.xhtml">
+<iframe src="file_bug428847-2.xhtml">
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug431082.html b/dom/base/test/test_bug431082.html
new file mode 100644
index 0000000000..aee6711f29
--- /dev/null
+++ b/dom/base/test/test_bug431082.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=431082
+-->
+<head>
+ <title>Test for Bug 431082</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=431082">Mozilla Bug 431082</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 431082 **/
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() { ok(true, "browser should not crash."); });
+addLoadEvent(SimpleTest.finish);
+
+</script>
+</pre>
+<!--
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<box id="a" observes="b">
+ <box id="b"/>
+</box>
+
+<box id="a" src="javascript:"/>
+<box id="b" src="javascript://"/>
+<editor observes="a"/>
+
+<script>
+function doe() {
+window.addEventListener('DOMAttrModified', function()
+{window.frameElement.remove();}, true);
+document.documentElement.appendChild(document.getElementsByTagName('box')[0]);
+}
+setTimeout(doe,0);
+</script>
+</window>
+-->
+<iframe src="data:application/xhtml+xml;charset=utf-8,%3Cwindow%20xmlns%3D%22http%3A//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%22%3E%0A%3Cbox%20%20id%3D%22a%22%20observes%3D%22b%22%3E%0A%20%20%3Cbox%20id%3D%22b%22/%3E%0A%3C/box%3E%0A%0A%3Cbox%20%20id%3D%22a%22%20%20src%3D%22javascript%3A%22/%3E%0A%3Cbox%20id%3D%22b%22%20src%3D%22javascript%3A//%22/%3E%0A%3Ceditor%20observes%3D%22a%22/%3E%0A%0A%3Cscript%3E%20%0Afunction%20doe%28%29%20%7B%0Awindow.addEventListener%28%27DOMAttrModified%27%2C%20function%28%29%20%7Bwindow.frameElement.parentNode.removeChild%28window.frameElement%29%3B%7D%2C%20true%29%3B%0Adocument.documentElement.appendChild%28document.getElementsByTagName%28%27box%27%29%5B0%5D%29%3B%0A%7D%0AsetTimeout%28doe%2C0%29%3B%0A%3C/script%3E%0A%3C/window%3E" style="width:1000px;height: 300px;"></iframe>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug431701.html b/dom/base/test/test_bug431701.html
new file mode 100644
index 0000000000..4009fc017a
--- /dev/null
+++ b/dom/base/test/test_bug431701.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=431701
+-->
+<head>
+ <meta charset="windows-1252">
+ <title>Test for Bug 431701</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=431701">Mozilla Bug 431701</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="one"></iframe>
+ <iframe id="two"></iframe>
+ <iframe id="three"></iframe>
+ <iframe id="four"></iframe>
+ <iframe id="five"></iframe>
+ <iframe id="six"></iframe>
+ <iframe id="seven"></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 431701 **/
+SimpleTest.waitForExplicitFinish();
+
+var docSources = [
+ "iframe1_bug431701.html",
+ "iframe2_bug431701.html",
+ "iframe3_bug431701.html",
+ "iframe4_bug431701.xml",
+ "iframe5_bug431701.xml",
+ "iframe6_bug431701.xml",
+ "iframe7_bug431701.xml",
+];
+
+for (let i = 0; i < docSources.length; ++i) {
+ document.getElementsByTagName("iframe")[i].src = docSources[i];
+}
+
+function frameDoc(id) {
+ return function() { return $(id).contentDocument; };
+}
+
+function createDoc() {
+ return document.implementation.createDocument('', 'html', null);
+}
+
+function xhrDoc(idx) {
+ return function() {
+ // Defy same-origin restrictions!
+ var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+ xhr.open("GET", docSources[idx], false);
+ xhr.send();
+ return xhr.responseXML;
+ };
+}
+
+// Each row has the document getter function, then the characterSet,
+// inputEncoding expected for that document.
+
+var tests = [
+ [ frameDoc("one"), "windows-1252" ],
+ [ frameDoc("two"), "UTF-8" ],
+ [ frameDoc("three"), "windows-1252" ],
+ [ frameDoc("four"), "UTF-8" ],
+ [ frameDoc("five"), "UTF-8" ],
+ [ frameDoc("six"), "UTF-8" ],
+ [ frameDoc("seven"), "windows-1252" ],
+ [ createDoc, "UTF-8" ],
+ [ xhrDoc(4), "UTF-8" ],
+ [ xhrDoc(5), "UTF-8" ],
+ [ xhrDoc(6), "windows-1252" ],
+];
+
+function doTest(idx) {
+ var [docGetter, expectedCharacterSet] = tests[idx];
+ var doc = docGetter();
+
+ // Have to be careful here to catch null vs ""
+ is(doc.characterSet, expectedCharacterSet, "Test " + idx + " characterSet");
+ is(doc.inputEncoding, expectedCharacterSet,
+ "Test " + idx + " inputEncoding");
+}
+
+addLoadEvent(function() {
+ SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], startTest);
+});
+
+function startTest() {
+ // sanity check
+ isnot("", null, "Shouldn't be equal!");
+
+ for (let i = 0; i < tests.length; ++i) {
+ doTest(i);
+ }
+
+ // Now check what xhr does
+ var xhr = new XMLHttpRequest();
+ xhr.open("POST", document.location.href);
+ xhr.send(createDoc());
+ is(SpecialPowers.wrap(xhr).channel.QueryInterface(SpecialPowers.Ci.nsIHttpChannel)
+ .getRequestHeader("Content-Type"),
+ "application/xml;charset=UTF-8", "Testing correct type on the wire");
+ xhr.abort();
+
+ SimpleTest.finish();
+};
+
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug431833.html b/dom/base/test/test_bug431833.html
new file mode 100644
index 0000000000..131b7d75a8
--- /dev/null
+++ b/dom/base/test/test_bug431833.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=431833
+-->
+<head>
+ <title>Test for Bug 431833</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script>
+ var loadsComplete = [];
+ function test(e) {
+ loadsComplete[e.target.id] = true;
+ }
+ window.addEventListener('DOMFrameContentLoaded',test,true);
+ </script>
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=431833">Mozilla Bug 431833</a>
+<p id="display">
+ <iframe id="f1" srcdoc="1"></iframe>
+ <iframe id="f2" srcdoc="2"></iframe>
+ <iframe id="f3" srcdoc="<iframe id='f4' src='data:text/html,3'></iframe>"></iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 431833 **/
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ function check(id) {
+ ok(loadsComplete[id], "DOMFrameContentLoaded didn't fire for " + id);
+ }
+ check("f1");
+ check("f2");
+ check("f3");
+ check("f4");
+ });
+
+addLoadEvent(SimpleTest.finish);
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug433533.html b/dom/base/test/test_bug433533.html
new file mode 100644
index 0000000000..12dd138109
--- /dev/null
+++ b/dom/base/test/test_bug433533.html
@@ -0,0 +1,300 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=433533
+-->
+<head>
+ <title>Test for Bug 433533</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=433533">Mozilla Bug 433533</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 433533 **/
+
+var input = document.createElement("input");
+input.setAttribute("type", "hidden");
+is(input.getAttribute("type"), "hidden", "Setting type attribute didn't work!");
+input.setAttribute("type", "hiDDen");
+is(input.getAttribute("type"), "hiDDen", "Type attribute didn't store the original value");
+is(input.type, "hidden", "Wrong input.type!");
+input.setAttribute("type", "HIDDEN");
+is(input.getAttribute("type"), "HIDDEN", "Type attribute didn't store the original value");
+is(input.type, "hidden", "Wrong input.type!");
+
+var td = document.createElement("td");
+td.setAttribute("scope", "rOW");
+is(td.getAttribute("scope"), "rOW", "Scope attribute didn't store the original value");
+td.setAttribute("scope", "row");
+is(td.getAttribute("scope"), "row", "Scope attribute didn't store the original value");
+td.setAttribute("colspan", "100k");
+is(td.getAttribute("colspan"), "100k", "Colspan attribute didn't store the original value");
+td.setAttribute("colspan", " 100 ");
+is(td.getAttribute("colspan"), " 100 ", "Colspan attribute didn't store the original value");
+td.setAttribute("colspan", "100");
+is(td.getAttribute("colspan"), "100", "Colspan attribute didn't store the original value");
+
+// Note, if colspan is negative, it is set to 1, because of backwards compatibility.
+// @see nsHTMLTableCellElement::ParseAttribute
+td.setAttribute("colspan", "-100k");
+is(td.getAttribute("colspan"), "-100k", "Colspan attribute didn't store the original value");
+td.setAttribute("colspan", " -100 ");
+is(td.getAttribute("colspan"), " -100 ", "Colspan attribute didn't store the original value");
+is(td.colSpan, 1, "Colspan reflection should be correct for ' -100 '");
+td.setAttribute("colspan", "-100");
+is(td.getAttribute("colspan"), "-100", "Colspan attribute didn't store the original value");
+is(td.colSpan, 1, "Colspan reflection should be correct for '-100'");
+
+
+td.setAttribute("colspan", "foobar");
+is(td.getAttribute("colspan"), "foobar", "Colspan attribute didn't store the original value");
+
+var iframe = document.createElement("iframe");
+iframe.setAttribute("marginwidth", "50%");
+is(iframe.getAttribute("marginwidth"), "50%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "50");
+is(iframe.getAttribute("marginwidth"), "50",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "0");
+is(iframe.getAttribute("marginwidth"), "0",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "0%");
+is(iframe.getAttribute("marginwidth"), "0%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "9999999999999999999999");
+is(iframe.getAttribute("marginwidth"), "9999999999999999999999",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "9999999999999999999999%");
+is(iframe.getAttribute("marginwidth"), "9999999999999999999999%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "-9999999999999999999999");
+is(iframe.getAttribute("marginwidth"), "-9999999999999999999999",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-9999999999999999999999%");
+is(iframe.getAttribute("marginwidth"), "-9999999999999999999999%",
+ "Marginwidth attribute didn't store the original value");
+
+
+// Test PRInt32 min/max value
+iframe.setAttribute("marginwidth", "2147483647");
+is(iframe.getAttribute("marginwidth"), "2147483647",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "2147483647%");
+is(iframe.getAttribute("marginwidth"), "2147483647%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "-2147483648");
+is(iframe.getAttribute("marginwidth"), "-2147483648",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-2147483648%");
+is(iframe.getAttribute("marginwidth"), "-2147483648%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "2147483646");
+is(iframe.getAttribute("marginwidth"), "2147483646",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "2147483647%");
+is(iframe.getAttribute("marginwidth"), "2147483647%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "-2147483647");
+is(iframe.getAttribute("marginwidth"), "-2147483647",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-2147483647%");
+is(iframe.getAttribute("marginwidth"), "-2147483647%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "2147483648");
+is(iframe.getAttribute("marginwidth"), "2147483648",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "2147483648%");
+is(iframe.getAttribute("marginwidth"), "2147483648%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "-2147483649");
+is(iframe.getAttribute("marginwidth"), "-2147483649",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-2147483649%");
+is(iframe.getAttribute("marginwidth"), "-2147483649%",
+ "Marginwidth attribute didn't store the original value");
+
+// some values 0 > x > NS_ATTRVALUE_INTEGERTYPE_MAXVALUE
+iframe.setAttribute("marginwidth", "134217726");
+is(iframe.getAttribute("marginwidth"), "134217726",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "134217727");
+is(iframe.getAttribute("marginwidth"), "134217727",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "134217728");
+is(iframe.getAttribute("marginwidth"), "134217728",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "134217729");
+is(iframe.getAttribute("marginwidth"), "134217729",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "134217726%");
+is(iframe.getAttribute("marginwidth"), "134217726%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "134217727%");
+is(iframe.getAttribute("marginwidth"), "134217727%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "134217728%");
+is(iframe.getAttribute("marginwidth"), "134217728%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "134217729%");
+is(iframe.getAttribute("marginwidth"), "134217729%",
+ "Marginwidth attribute didn't store the original value");
+
+// some values 0 < x < NS_ATTRVALUE_INTEGERTYPE_MINVALUE
+iframe.setAttribute("marginwidth", "-134217727");
+is(iframe.getAttribute("marginwidth"), "-134217727",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-134217728");
+is(iframe.getAttribute("marginwidth"), "-134217728",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-134217729");
+is(iframe.getAttribute("marginwidth"), "-134217729",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-134217730");
+is(iframe.getAttribute("marginwidth"), "-134217730",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-134217727%");
+is(iframe.getAttribute("marginwidth"), "-134217727%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-134217728%");
+is(iframe.getAttribute("marginwidth"), "-134217728%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-134217729%");
+is(iframe.getAttribute("marginwidth"), "-134217729%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-134217730%");
+is(iframe.getAttribute("marginwidth"), "-134217730%",
+ "Marginwidth attribute didn't store the original value");
+
+iframe.setAttribute("marginwidth", "-0");
+is(iframe.getAttribute("marginwidth"), "-0",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-0%");
+is(iframe.getAttribute("marginwidth"), "-0%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", " 0 ");
+is(iframe.getAttribute("marginwidth"), " 0 ",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", " 0% ");
+is(iframe.getAttribute("marginwidth"), " 0% ",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-50%");
+is(iframe.getAttribute("marginwidth"), "-50%",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "-50");
+is(iframe.getAttribute("marginwidth"), "-50",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", " -50% ");
+is(iframe.getAttribute("marginwidth"), " -50% ",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", " -50 ");
+is(iframe.getAttribute("marginwidth"), " -50 ",
+ "Marginwidth attribute didn't store the original value");
+iframe.setAttribute("marginwidth", "foobar");
+is(iframe.getAttribute("marginwidth"), "foobar",
+ "Marginwidth attribute didn't store the original value");
+
+var bd = document.createElement("body");
+bd.setAttribute("bgcolor", "red");
+is(bd.getAttribute("bgcolor"), "red", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "red", ".bgColor didn't return the right value!");
+
+bd.setAttribute("bgcolor", " red ");
+is(bd.getAttribute("bgcolor"), " red ", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, " red ", ".bgColor didn't return the right value!");
+
+bd.setAttribute("bgcolor", "#ff0000");
+is(bd.getAttribute("bgcolor"), "#ff0000", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "#ff0000", ".bgColor didn't return the right value!");
+
+bd.setAttribute("bgcolor", "#f00");
+is(bd.getAttribute("bgcolor"), "#f00", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "#f00", ".bgColor didn't return the right value!");
+
+bd.setAttribute("bgcolor", " #ff0000 ");
+is(bd.getAttribute("bgcolor"), " #ff0000 ", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, " #ff0000 ", ".bgColor didn't return the right value!");
+
+bd.setAttribute("bgcolor", "nonsense(complete)");
+is(bd.getAttribute("bgcolor"), "nonsense(complete)", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "nonsense(complete)", ".bgColor didn't return the right value!");
+
+// same test again setting the prop
+bd.bgColor = "red";
+is(bd.getAttribute("bgcolor"), "red", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "red", ".bgColor didn't return the right value!");
+
+bd.bgColor = " red ";
+is(bd.getAttribute("bgcolor"), " red ", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, " red ", ".bgColor didn't return the right value!");
+
+bd.bgColor = "#ff0000";
+is(bd.getAttribute("bgcolor"), "#ff0000", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "#ff0000", ".bgColor didn't return the right value!");
+
+bd.bgColor = "#f00";
+is(bd.getAttribute("bgcolor"), "#f00", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "#f00", ".bgColor didn't return the right value!");
+
+bd.bgColor = " #ff0000 ";
+is(bd.getAttribute("bgcolor"), " #ff0000 ", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, " #ff0000 ", ".bgColor didn't return the right value!");
+
+bd.bgColor = "nonsense(complete)";
+is(bd.getAttribute("bgcolor"), "nonsense(complete)", "Bgcolor attribute didn't store the original value");
+is(bd.bgColor, "nonsense(complete)", ".bgColor didn't return the right value!");
+
+// equal color, unequal string
+var f1 = document.createElement("font");
+var f2 = document.createElement("font");
+var f3 = document.createElement("font");
+f1.color = "#f00";
+f2.color = "#ff0000";
+f3.color = "red";
+isnot(f1.color, f2.color, "#f00 and #ff0000 should not compare equal");
+isnot(f1.color, f3.color, "#f00 and red should not compare equal");
+isnot(f2.color, f3.color, "#ff0000 and red should not compare equal");
+
+isnot(f1.getAttribute("color"), f2.getAttribute("color"),
+ "#f00 and #ff0000 should not compare equal [attr]");
+isnot(f1.getAttribute("color"), f3.getAttribute("color"),
+ "#f00 and red should not compare equal [attr]");
+isnot(f2.getAttribute("color"), f3.getAttribute("color"),
+ "#ff0000 and red should not compare equal [attr]");
+
+var video = document.createElement("video");
+video.setAttribute("playbackrate", "1");
+is(video.getAttribute('playbackrate'), "1",
+ "Playbackrate attribute didn't store the original value");
+video.setAttribute("playbackrate", "1.5");
+is(video.getAttribute('playbackrate'), "1.5",
+ "Playbackrate attribute didn't store the original value");
+video.setAttribute("playbackrate", "999999999999999999");
+is(video.getAttribute('playbackrate'), "999999999999999999",
+ "Playbackrate attribute didn't store the original value");
+video.setAttribute("playbackrate", "-999999999999999999");
+is(video.getAttribute('playbackrate'), "-999999999999999999",
+ "Playbackrate attribute didn't store the original value");
+video.setAttribute("playbackrate", "foo");
+is(video.getAttribute('playbackrate'), "foo",
+ "Playbackrate attribute didn't store the original value");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug433662.html b/dom/base/test/test_bug433662.html
new file mode 100644
index 0000000000..ec30775a21
--- /dev/null
+++ b/dom/base/test/test_bug433662.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=433662
+-->
+<title>Test for Bug 433662</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=433662">Mozilla Bug 433662</a>
+<script>
+
+/** Test for Bug 433662 **/
+var range = document.createRange();
+range.setStart(document.body, 0);
+range.insertNode(document.createComment("abc"));
+is(document.body.firstChild.nodeType, Node.COMMENT_NODE,
+ "Comment must be inserted (start of node)");
+is(document.body.firstChild.nodeValue, "abc",
+ "Comment must have right contents (start of node)");
+is(range.endOffset, 1,
+ "insertNode() needs to include the newly-added node (start of node)");
+
+range.setStart(document.body, document.body.childNodes.length);
+range.insertNode(document.createComment("def"));
+is(document.body.lastChild.nodeType, Node.COMMENT_NODE,
+ "Comment must be inserted (end of node)");
+is(document.body.lastChild.nodeValue, "def",
+ "Comment must have right contents (end of node)");
+is(range.endOffset, document.body.childNodes.length,
+ "insertNode() needs to include the newly-added node (end of node)");
+
+</script>
diff --git a/dom/base/test/test_bug435425.html b/dom/base/test/test_bug435425.html
new file mode 100644
index 0000000000..beb97e0776
--- /dev/null
+++ b/dom/base/test/test_bug435425.html
@@ -0,0 +1,430 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=435425
+-->
+<head>
+ <title>Test for Bug 435425</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=435425">Mozilla Bug 435425</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 435425 **/
+
+var upload = null;
+var currentEvents = null;
+var expectedResponseText = null;
+var uploadTotal = 0;
+var currentProgress = -1;
+
+function logEvent(evt) {
+ var i = 0;
+ while ((currentEvents.length != i) &&
+ currentEvents[i].optional &&
+ ((currentEvents[i].type != evt.type) ||
+ !(evt.target instanceof currentEvents[i].target))) {
+ ++i;
+ }
+
+ if (evt.target instanceof XMLHttpRequestUpload) {
+ if (evt.type == "loadstart") {
+ uploadTotal = evt.total
+ } else {
+ if (evt.type == "progress") {
+ is(evt.lengthComputable, evt.total != 0, "event(" + evt.type + ").lengthComputable should be " + (evt.total != 0) + ".");
+ }
+ if (evt.total != uploadTotal && evt.total != 0) {
+ ok(false, "event(" + evt.type + ").total should not change during upload except to become 0 on error/abort/timeout.");
+ }
+ }
+ }
+
+ // There can be any number of repeated progress events, so special-case this.
+ if (evt.type == "progress") {
+ // Progress events can repeat, but their "loaded" value must increase.
+ if (currentProgress >= 0) {
+ ok(currentProgress < evt.loaded, "Progress should increase, got " +
+ evt.loaded + " after " + currentProgress);
+ currentProgress = evt.loaded;
+ return; // stay at the currentEvent, since we got progress instead of it.
+ }
+ // Starting a new progress event group.
+ currentProgress = evt.loaded;
+ } else {
+ // Reset the progress indicator on any other event type.
+ currentProgress = -1;
+ }
+
+ ok(i != currentEvents.length, "Extra or wrong event?");
+ is(evt.type, currentEvents[i].type, "Wrong event!")
+ ok(evt.target instanceof currentEvents[i].target,
+ "Wrong event target [" + evt.target + "," + evt.type + "]!");
+
+ // If we handled non-optional event, remove all optional events before the
+ // handled event and then the non-optional event from the list.
+ if (!currentEvents[i].optional) {
+ for (;i != -1; --i) {
+ currentEvents.shift();
+ }
+ }
+}
+
+function hasPendingNonOptionalEvent(ev) {
+ var i = 0;
+ while (i < currentEvents.length) {
+ if (!currentEvents[i].optional && currentEvents[i].type == ev)
+ return true;
+ ++i;
+ }
+ return false;
+}
+
+function maybeStop(evt) {
+ logEvent(evt);
+ if (!hasPendingNonOptionalEvent("loadend"))
+ nextTest();
+}
+
+function openXHR(xhr, method, url, privileged) {
+ if (privileged)
+ SpecialPowers.wrap(xhr).open(method, url);
+ else
+ xhr.open(method, url);
+}
+
+function start(obj) {
+ let xhr = new XMLHttpRequest();
+ upload = xhr.upload;
+ currentEvents = obj.expectedEvents;
+ expectedResponseText = obj.withUpload;
+ currentProgress = -1;
+ xhr.onload =
+ function(evt) {
+ if (expectedResponseText) {
+ is(evt.target.responseText, expectedResponseText, "Wrong responseText");
+ }
+ logEvent(evt);
+ }
+ xhr.onerror =
+ function(evt) {
+ logEvent(evt);
+ }
+ xhr.onabort =
+ function(evt) {
+ logEvent(evt);
+ }
+ xhr.onloadend =
+ function (evt) {
+ maybeStop(evt);
+ }
+ xhr.onloadstart =
+ function (evt) {
+ logEvent(evt);
+ }
+ xhr.onprogress =
+ function (evt) {
+ logEvent(evt);
+ }
+
+ if ("upload" in xhr) {
+ xhr.upload.onloadstart =
+ function (evt) {
+ logEvent(evt);
+ }
+ xhr.upload.onprogress =
+ function (evt) {
+ logEvent(evt);
+ }
+ xhr.upload.onload =
+ function (evt) {
+ logEvent(evt);
+ }
+ xhr.upload.onerror =
+ function (evt) {
+ logEvent(evt);
+ }
+ xhr.upload.onabort =
+ function (evt) {
+ logEvent(evt);
+ }
+ xhr.upload.onloadend =
+ function (evt) {
+ maybeStop(evt);
+ }
+ }
+
+ try {
+ var methodIsGet = (obj.method == "GET");
+ var url;
+ var privileged = false;
+ if (obj.testRedirectError) {
+ url = "bug435425_redirect.sjs";
+ } else if (obj.testNetworkError) {
+ url = "http://nosuchdomain.localhost";
+ privileged = true;
+ } else {
+ url = "bug435425.sjs";
+ if (obj.withUpload && methodIsGet) {
+ url += "?" + obj.withUpload;
+ }
+ }
+ openXHR(xhr, obj.method, url, privileged);
+ xhr.send(!methodIsGet ? obj.withUpload : null);
+ if (obj.testAbort) {
+ xhr.abort();
+ }
+ } catch (ex) {
+ ok(false, ex);
+ }
+}
+
+var none = null;
+var small = "";
+var mid = "";
+var large = "";
+
+
+for (var smallLength = 0; smallLength < (0x00000000 + 2); ++smallLength) {
+ small += "A";
+}
+
+for (var midLength = 0; midLength < (0x00000FFF + 2); ++midLength) {
+ mid += "A";
+}
+
+for (var largeLength = 0; largeLength < (0x0000FFFF + 2); ++largeLength) {
+ large += "A";
+}
+
+const XHR = XMLHttpRequest;
+const UPLOAD = XMLHttpRequestUpload;
+
+var tests =
+ [
+ { method: "GET", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+
+ { method: "GET", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+
+ { method: "GET", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+
+ { method: "GET", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "GET", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+
+ { method: "POST", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+
+ { method: "POST", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: false},
+ {target: UPLOAD, type: "load", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: true},
+ {target: UPLOAD, type: "abort", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: true},
+ {target: UPLOAD, type: "error", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "error", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+
+ { method: "POST", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: false},
+ {target: UPLOAD, type: "load", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: true},
+ {target: UPLOAD, type: "abort", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: true},
+ {target: UPLOAD, type: "error", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "error", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+
+ { method: "POST", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: false},
+ {target: UPLOAD, type: "load", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "progress", optional: false},
+ {target: XHR, type: "load", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: true},
+ {target: UPLOAD, type: "abort", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "progress", optional: true},
+ {target: XHR, type: "abort", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "progress", optional: true},
+ {target: UPLOAD, type: "error", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+ { method: "POST", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: true,
+ expectedEvents: [{target: XHR, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "loadstart", optional: false},
+ {target: UPLOAD, type: "error", optional: false},
+ {target: UPLOAD, type: "loadend", optional: false},
+ {target: XHR, type: "error", optional: false},
+ {target: XHR, type: "loadend", optional: false}]},
+];
+
+function runTest() {
+ var test = tests.shift();
+ start(test);
+}
+
+function nextTest() {
+ if (tests.length) {
+ setTimeout("runTest()", 0);
+ } else {
+ SimpleTest.finish();
+ }
+}
+
+ok("upload" in (new XMLHttpRequest()), "XMLHttpRequest.upload isn't supported!");
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug444322.html b/dom/base/test/test_bug444322.html
new file mode 100644
index 0000000000..e9254d1015
--- /dev/null
+++ b/dom/base/test/test_bug444322.html
@@ -0,0 +1,2588 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Firefox 3 Bug #444322 example</title>
+
+<script type="text/javascript" src="444322.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script type="text/javascript">
+function getFile(url) {
+ if (window.XMLHttpRequest) {
+ AJAX=new XMLHttpRequest();
+ } else {
+ AJAX=new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ if (AJAX) {
+ AJAX.open("GET", url, false);
+ AJAX.send(null);
+ return AJAX.responseText;
+ } else {
+ return false;
+ }
+}
+var text = getFile("444322.txt");
+var x = 'scott';
+</script>
+ </head>
+<body>
+<p id="display"></p>
+<p>This page demonstrates the bug described in <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=444322#c24" target="_blank">Bugzilla #444322</a>.</p>
+<p>In the &lt;head&gt; section of the document, the global var x is set to "scott". In the &lt;body&gt;, a Javascript statement writes the value of x to the screen.</p>
+<p>The expected output is: <b>scott</b>.</p>
+<p>The actual output is: <b>
+ <script type="text/javascript">document.write(x); is(x, "scott", "x is correct")</script></b></p>
+<p>This shows that the Javascript in the &lt;head&gt; is not completing before the script in the &lt;body&gt; is executed.</p>
+<p>For this bug to occur, the following circumstances must be met:
+ <ol>
+ <li>An external Javascript file must be loaded on the page. It doesn't matter what code is in the file, and it can in fact be blank as test.js is in this example.
+ <li>A synchronous AJAX call must be made in the &lt;head&gt;. Again, the file being loaded can be empty. An alert() call will also work.
+ <li>The size of the .html (or whatever) file must be relatively large -- in our tests anything above 169,609 bytes did the trick (hence the large amount of text following this explanation).
+ </ol>
+<p>On some occasions we saw the issue <i>not</i> occur if the page was not cached or if it was refreshed, but it would then occur if the page was hit again from a link or by pressing enter in the location bar. This example seems to cause the bug whether the page is cached or not.</p>
+<br />
+<hr />
+<br />
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras ac velit sed tellus facilisis euismod. Proin vel nulla vel turpis tristique dignissim. Donec lacus ipsum, eleifend ut, volutpat a, ultrices adipiscing, arcu. Etiam ligula dolor, adipiscing ut, porta vitae, bibendum non, dolor. Mauris ligula. Sed placerat tincidunt elit. Vestibulum non libero. Curabitur cursus tortor id sem. Integer consectetuer auctor lacus. Proin nisl nisi, pulvinar eget, pharetra at, aliquam eu, velit. Morbi fringilla. Quisque faucibus, mauris posuere vulputate interdum, lectus libero sollicitudin tellus, sit amet ultrices enim purus ac mauris. Pellentesque sit amet mauris eu ante aliquet egestas. Mauris dapibus, velit consectetuer tristique luctus, enim augue pulvinar libero, fringilla dictum lectus felis eu ligula. In ac lorem.<br /><br />
+
+Integer laoreet. Ut ultricies arcu nec est. Aenean varius nisl ut odio. Nullam arcu. Vestibulum non pede. Proin vel est. Nam condimentum fermentum dui. Donec at arcu. Donec at libero adipiscing odio mattis dapibus. Suspendisse libero neque, faucibus sed, facilisis et, convallis sit amet, justo. Duis purus tortor, ornare ac, convallis ut, pretium et, tellus. Nam accumsan, ipsum eget accumsan mollis, sapien dolor adipiscing metus, id tincidunt ipsum metus sed nulla. Praesent hendrerit lectus eget tortor. Morbi id lectus et elit ultrices hendrerit. Cras gravida velit sed mauris. Proin lacinia tempus est. Sed sapien tortor, fringilla vel, elementum in, volutpat ac, ante. Vivamus eu tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Mauris in sem ac felis pretium placerat. Donec tempus cursus sem. Aliquam scelerisque porttitor sem. Curabitur consectetuer, pede vitae aliquam aliquet, sapien lacus vehicula neque, ut rhoncus nibh neque sed velit. In rhoncus, nulla eu dignissim egestas, diam nibh hendrerit mauris, condimentum laoreet sapien arcu quis mi. Sed euismod sem. Nulla non ligula sed lacus tempor molestie. Quisque varius. In hac habitasse platea dictumst. Sed felis ipsum, consequat et, blandit vitae, tincidunt id, quam. Nunc nunc. Duis gravida. In massa neque, cursus quis, rutrum sed, semper quis, erat. Donec enim. Suspendisse condimentum eros vel elit. Vestibulum adipiscing erat id lorem. Maecenas enim dui, cursus a, pulvinar ac, rutrum sed, sem. Suspendisse gravida ante vel lectus.<br /><br />
+
+Vestibulum molestie, ante at dignissim venenatis, pede urna dictum arcu, vel ullamcorper ligula eros eget metus. Pellentesque nec nisl. Morbi ut nibh. Aenean mauris. Mauris rutrum justo nec velit. Nunc condimentum tortor id augue. Quisque semper massa eget nibh. Maecenas ac odio pretium lorem tincidunt faucibus. Sed congue. Cras sit amet orci ut ligula cursus congue. Etiam laoreet lacus sit amet tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus accumsan. Ut gravida urna hendrerit leo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /><br />
+
+Proin viverra augue in felis. Mauris sed neque. Proin libero. Donec elementum fermentum lacus. Nam et tortor eu purus porta interdum. Suspendisse eget erat et massa vehicula accumsan. Aliquam est. In sollicitudin sapien a tellus. Sed placerat tellus non velit. Nulla facilisi. Donec quam urna, tempus et, egestas ac, pretium ac, risus. Sed venenatis tempor dui. Nam condimentum, erat id fermentum pretium, ante ligula bibendum lorem, accumsan viverra dui augue a pede.<br /><br />
+
+Nulla est dui, mattis id, scelerisque eu, hendrerit ut, tellus. Aliquam rhoncus. Vivamus lacinia tortor id justo. Pellentesque id nisi eget sem luctus venenatis. Nunc dolor. Aliquam consectetuer metus ac odio. Sed congue. Vivamus risus eros, bibendum et, congue quis, hendrerit vel, purus. Curabitur sed massa ut augue feugiat imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec enim orci, convallis sit amet, semper sed, vehicula at, turpis.<br /><br />
+
+Nam quam mauris, iaculis eget, suscipit vel, laoreet eu, dui. Duis leo. Aenean sit amet nunc a metus fermentum ornare. In et est. Vestibulum vitae tortor. Nunc non risus. Nulla ullamcorper nulla nec eros. Ut mi neque, dapibus at, semper ut, faucibus faucibus, ligula. Suspendisse lectus lacus, consectetuer a, imperdiet id, eleifend quis, nibh. Vestibulum sit amet sem. Nam auctor feugiat augue. Nullam non nulla vitae mi ornare aliquet. In mollis. Pellentesque ac pede. Suspendisse placerat tellus pharetra augue. Sed massa magna, scelerisque non, lobortis ac, rhoncus in, purus. Vestibulum vitae quam vel est tristique fringilla. Fusce laoreet interdum mauris.<br /><br />
+
+Cras lectus elit, pharetra ut, iaculis vel, mattis consectetuer, orci. Duis ut justo vitae massa scelerisque accumsan. Morbi et ipsum nec dolor tincidunt gravida. Donec ac sem. Pellentesque dictum erat. Vestibulum lobortis lorem vel nisi. Suspendisse potenti. Cras fermentum est a sem. Nunc suscipit, velit ac vestibulum aliquet, nulla orci fringilla lectus, ut imperdiet odio nunc nec ligula. Integer nisl lacus, interdum sit amet, tempor vitae, ultricies id, elit. Nam augue turpis, adipiscing at, vestibulum ut, vehicula vitae, urna. In hac habitasse platea dictumst. Suspendisse arcu ligula, imperdiet eu, vestibulum non, posuere id, enim. Nullam ornare erat at orci. Quisque eget purus. Nunc ultrices felis aliquam ipsum. Proin gravida. Sed ipsum.<br /><br />
+
+Sed vehicula vehicula erat. Sed dui nulla, adipiscing a, ultricies sed, lacinia eget, justo. Sed nisi justo, gravida nec, placerat volutpat, sollicitudin eu, sapien. In orci. Nam convallis neque vitae eros. Curabitur mattis lectus eget tortor. Donec neque. Proin dui pede, ultrices hendrerit, volutpat nec, adipiscing ac, urna. Fusce aliquam condimentum felis. Etiam sodales varius risus. Nulla nisl diam, pharetra sit amet, vestibulum nec, tincidunt hendrerit, neque. Nullam nunc. Curabitur pellentesque, lacus at lobortis vehicula, erat lectus commodo enim, ut aliquet orci felis eget eros. Donec a augue sit amet lacus pharetra semper. Praesent porta dignissim nunc. Suspendisse ut leo at sapien convallis malesuada. Proin posuere interdum massa. Pellentesque mollis, dolor ut tincidunt euismod, nunc tellus adipiscing lectus, nec volutpat nulla nulla ac nulla.<br /><br />
+
+Curabitur eu ante. Pellentesque nulla diam, feugiat nec, suscipit eget, blandit vel, odio. Cras ullamcorper metus vel lectus. Fusce pulvinar. Etiam convallis adipiscing ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum felis. Donec euismod purus sit amet dui. Ut iaculis. Curabitur non ipsum. Mauris augue. Proin lacinia. Suspendisse potenti. Suspendisse feugiat sodales leo. Aliquam erat volutpat. Mauris fermentum nisi non nisi. Aliquam velit. Donec iaculis, justo sit amet tempus iaculis, sapien nulla congue orci, a elementum massa sem non velit.<br /><br />
+
+Etiam quis urna quis eros dapibus aliquam. Donec non risus. Curabitur pretium. Suspendisse fermentum ligula eu augue. Curabitur sollicitudin. Pellentesque porta mauris. In hac habitasse platea dictumst. Nullam cursus, arcu eu malesuada porta, magna lacus ultricies eros, sed lacinia erat justo vel nibh. Etiam ultricies placerat sem. Pellentesque nec erat. Etiam augue.<br /><br />
+
+Quisque odio. Nullam eu libero in augue convallis pellentesque. Duis placerat. Curabitur porta leo eu orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean justo. Nam vehicula. Vivamus ante elit, iaculis a, rhoncus vel, interdum et, libero. Fusce in sem scelerisque libero vehicula rhoncus. Sed vitae nibh. Curabitur molestie dictum magna. Quisque tristique purus vel ante. Fusce et erat. Phasellus erat. Quisque pellentesque. Integer velit lacus, pretium et, auctor vel, molestie malesuada, purus.<br /><br />
+
+Morbi purus enim, gravida vel, elementum et, aliquam in, ante. Nam eget massa. Donec quam diam, posuere at, volutpat sit amet, laoreet eu, tellus. Sed eu ipsum et nisi porta ullamcorper. In hac habitasse platea dictumst. Sed non dolor nec lorem hendrerit porta. Etiam sollicitudin ornare sapien. Pellentesque a mi. Mauris porttitor velit vel felis. Duis est. Donec sollicitudin. Cras vel justo adipiscing ligula bibendum pellentesque. Maecenas justo dolor, porttitor et, malesuada in, dictum sit amet, leo. Praesent molestie porta nibh. Aliquam facilisis.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus eget nisl. Curabitur libero nibh, iaculis non, vehicula non, gravida sit amet, augue. Praesent feugiat massa id ligula. Fusce non orci. Suspendisse fringilla dictum est. Nulla condimentum, risus sit amet accumsan fringilla, eros orci tristique risus, a sagittis ligula dolor in metus. Nunc sem dolor, sodales ac, tempor nec, commodo a, sapien. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Proin viverra nulla placerat est. Suspendisse at lectus. Proin tristique, nulla vitae tincidunt elementum, nisi urna pellentesque dui, nec egestas urna lacus ac nibh.<br /><br />
+
+Morbi et nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur molestie. Cras mauris dui, fringilla ut, aliquam semper, condimentum vitae, tellus. Aliquam in nibh nec justo porta viverra. Duis consectetuer mi in nunc. Duis ac felis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur eros tortor, ultricies id, accumsan ut, ultrices ac, nisi. Fusce elementum pede id nisi. Mauris venenatis nibh quis enim.<br /><br />
+
+Pellentesque sed odio a urna iaculis facilisis. Ut placerat faucibus nibh. Maecenas turpis pede, aliquet a, condimentum nec, dignissim et, nisl. Vivamus ac nulla. Nulla facilisi. Nam at lorem a ligula consequat semper. Nulla facilisi. Phasellus non nulla non diam faucibus blandit. Cras viverra, leo sit amet commodo dictum, enim ipsum scelerisque purus, ac malesuada ligula ligula ut metus. Ut vel nunc. Phasellus euismod ipsum et sem. Quisque luctus pretium arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras adipiscing viverra diam. Aenean sed ipsum id felis condimentum porta. Quisque eros dolor, fringilla ac, scelerisque ac, placerat eu, tortor.<br /><br />
+
+Quisque aliquet, mi vulputate dignissim molestie, orci diam aliquam nulla, commodo euismod neque arcu eu enim. Sed sed mi. Donec scelerisque tincidunt arcu. Nunc augue elit, cursus id, ultrices ut, lobortis id, nibh. Quisque nulla sem, scelerisque sed, convallis ut, aliquam a, purus. Proin nulla nunc, scelerisque in, aliquet vel, gravida eu, pede. Donec eget nunc eu tortor adipiscing imperdiet. Vestibulum eu quam id lacus hendrerit ornare. In hac habitasse platea dictumst. Sed molestie mollis mauris. Nunc porta.<br /><br />
+
+Maecenas condimentum ipsum eget elit. Donec sit amet mi. Nulla non neque in quam interdum lobortis. Suspendisse potenti. Cras orci dui, eleifend ut, ultrices at, volutpat at, orci. Mauris justo erat, pharetra vel, molestie a, varius ut, dolor. Etiam feugiat lacus id est. Vivamus lobortis, justo a cursus ultricies, turpis tellus tincidunt tortor, nec dignissim turpis nisl vel pede. Etiam eu turpis. Donec eget justo. Aenean gravida elit eget quam. Proin commodo, ligula sed mattis accumsan, risus erat pulvinar lorem, vitae consectetuer arcu magna in risus. Vivamus nulla. Suspendisse egestas nisl quis urna. Ut quis eros. Mauris ligula velit, aliquet non, venenatis et, rhoncus vitae, lectus. Nam ornare quam a augue.<br /><br />
+
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut eros magna, rhoncus et, condimentum in, scelerisque commodo, ipsum. Nulla hendrerit, est a varius ornare, velit pede condimentum magna, eu rhoncus odio diam at sem. Sed cursus euismod libero. Maecenas sit amet mauris. Sed egestas ante vitae metus. Nulla lacus. In arcu ante, ultrices quis, suscipit ac, sagittis eu, neque. Duis laoreet. Maecenas mi. Quisque urna metus, tincidunt tincidunt, imperdiet sit amet, molestie at, odio. Etiam ac felis. Praesent ligula. Phasellus tempus nibh. Pellentesque dapibus. Curabitur ultricies leo a est. Praesent sit amet arcu. Suspendisse fermentum lectus eget arcu. Ut est. Aenean sit amet nisl non urna suscipit ornare.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur ut lacus id ipsum condimentum pellentesque. Nunc suscipit. Maecenas sagittis eros at lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris porttitor mi in tellus. Proin vel sem ac est euismod iaculis. Aliquam hendrerit nisl vitae nibh. Sed mollis. Nulla facilisi. Vivamus faucibus quam.<br /><br />
+
+Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut et turpis non arcu fringilla pellentesque. Nullam interdum facilisis felis. Mauris tincidunt. Donec luctus, lorem sed lacinia ornare, enim quam sagittis lacus, ut porttitor nulla nisi eget mi. Nullam sagittis. Sed dapibus, turpis non eleifend sodales, risus massa hendrerit neque, volutpat aliquam nulla tellus eu dui. Pellentesque iaculis fermentum mi. Nam cursus ligula et nibh. Fusce tortor nibh, bibendum vitae, pharetra et, volutpat sed, urna.<br /><br />
+
+Nulla facilisi. Nulla non ante. Etiam vel nunc. Cras luctus auctor nibh. Suspendisse varius arcu a risus. Duis interdum malesuada tortor. Sed vel mauris. Mauris sed lorem. Aliquam purus. Vivamus sit amet neque. Nulla ultrices, ante ac porttitor ultrices, enim dui varius ipsum, tincidunt malesuada felis turpis non turpis. Nullam egestas, massa venenatis dictum imperdiet, urna est rhoncus magna, a fermentum ligula dolor malesuada lacus. Proin ac dui.<br /><br />
+
+Donec vestibulum magna quis enim. Nam dui nisl, lacinia non, dapibus at, mollis et, elit. Aliquam tempor nulla vitae metus. Integer varius convallis massa. Ut tempus, sem vel commodo aliquam, tellus justo placerat magna, ac mollis ipsum nulla ornare arcu. Cras risus nibh, eleifend in, scelerisque id, consequat quis, erat. Maecenas venenatis augue id odio. Cras libero. Donec sed eros. Etiam varius odio id nunc. Nam euismod urna a tellus. In non sem. In aliquet. Morbi sodales magna eu enim. Cras tristique.<br /><br />
+
+Nam quis quam eu quam euismod tristique. Donec ac velit. Ut a velit. Suspendisse eu turpis. Integer eros leo, euismod eu, rutrum eget, imperdiet sed, risus. Donec congue sapien. Nulla venenatis magna ac quam. Fusce purus odio, pharetra eget, vulputate non, auctor quis, magna. Nulla facilisi. Ut sagittis, mauris at cursus aliquam, ipsum mi faucibus justo, vel pharetra metus felis ac dolor. Donec elementum arcu quis tellus. Quisque mattis sem eu metus. Duis tempor elit non sem. Cras ultrices risus.<br /><br />
+
+Integer pulvinar. Vestibulum blandit dolor et lacus. Aliquam varius arcu ac arcu ornare pharetra. Phasellus ut sapien nec neque posuere feugiat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus pharetra semper justo. Sed ut elit. Aenean aliquet euismod quam. Mauris turpis justo, lacinia at, blandit sit amet, molestie tristique, sapien. Integer et urna sit amet lectus facilisis pulvinar.<br /><br />
+
+Phasellus vitae elit non odio pulvinar faucibus. Maecenas elementum. Fusce bibendum, odio eget rutrum aliquam, velit felis dapibus elit, in dapibus libero velit eget arcu. Sed dolor enim, porta eget, luctus in, cursus nec, erat. Duis pretium. Cras volutpat velit in dui. Fusce vitae enim. Nunc ornare dolor non purus. Maecenas pulvinar velit id mauris. Vestibulum in erat. Mauris in metus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin at dui nec ipsum suscipit ultricies.<br /><br />
+
+Integer tristique enim sed neque. Sed sapien sapien, suscipit at, bibendum sed, iaculis a, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus sagittis accumsan lectus. Maecenas tincidunt semper erat. In vitae arcu. Ut vulputate tempus magna. Nam erat. Sed mi. Vestibulum mauris. Maecenas et sem. Cras risus justo, hendrerit ut, cursus nec, pretium in, ipsum. Sed molestie lectus sed arcu consectetuer vulputate. Nunc mollis posuere dolor. Morbi nec velit a libero pharetra facilisis. Cras tincidunt.<br /><br />
+
+Donec rutrum luctus augue. Donec mattis commodo erat. Aenean sodales. Duis convallis metus id massa. Integer eget lorem et lectus sodales cursus. Integer commodo, tellus ut consequat placerat, nibh nisi malesuada nulla, eu aliquet metus mauris id nulla. Sed sagittis. Nam in mauris. Quisque eget ipsum. Suspendisse enim arcu, semper vitae, tincidunt dapibus, malesuada ac, dolor. Donec adipiscing auctor sem. Phasellus vitae pede. Integer lectus risus, ultrices non, euismod sed, condimentum et, lacus. Suspendisse potenti. Praesent tristique iaculis nulla. Curabitur sagittis. Aliquam erat volutpat. Donec feugiat, lectus vel tincidunt blandit, nisi mauris venenatis mi, id vehicula quam ante eget massa. Suspendisse volutpat sodales lorem. Nunc leo odio, dictum a, rutrum ac, aliquam at, felis.<br /><br />
+
+Vestibulum blandit. Sed volutpat mi nec massa. Aliquam erat volutpat. Nam eu erat et turpis accumsan semper. Nam justo. Sed lacinia. Pellentesque dignissim diam. Suspendisse consectetuer mattis massa. Praesent feugiat orci a augue. Donec eget tellus. Vestibulum suscipit neque vel eros. Nunc libero. Sed scelerisque nunc et sapien. Nulla sit amet ante convallis felis dapibus consectetuer. Pellentesque iaculis erat eu purus viverra facilisis. Duis vestibulum, felis ac sollicitudin interdum, augue eros tincidunt felis, sit amet eleifend quam nibh eu sem.<br /><br />
+
+Duis fermentum, urna et commodo porta, nisl ante egestas ante, in varius sem lacus eget turpis. Nullam dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum velit quis lorem. Nulla facilisi. Nunc rutrum diam eu magna. Phasellus eleifend, tellus ut elementum fringilla, turpis neque ornare elit, et gravida nisi odio ac lacus. Integer non velit vitae pede laoreet molestie. Nullam in tellus at turpis interdum rhoncus. Donec ut purus vel elit lobortis rutrum. Nullam est leo, porta eu, facilisis et, tempus vel, massa. Vivamus eu purus. Sed volutpat consectetuer tortor. Aliquam nec lacus. Aliquam purus est, tempor in, auctor vel, ornare nec, diam. Duis ipsum erat, vestibulum lacinia, tincidunt eget, sodales nec, nibh. Maecenas convallis vulputate est. Quisque enim.<br /><br />
+
+Aenean ut dui. Sed eleifend ligula sit amet odio. Aliquam mi. Integer metus ante, commodo quis, ullamcorper non, euismod in, est. In hac habitasse platea dictumst. Donec pede erat, venenatis a, pretium et, placerat vitae, velit. Cras lectus diam, ultricies a, interdum quis, placerat at, diam. Nam aliquet orci in velit luctus ornare. Donec a diam quis mi iaculis aliquam. Suspendisse iaculis. Duis nec lorem. Sed vehicula massa et urna. Morbi lorem. Proin et eros eget tellus eleifend viverra. Sed suscipit.<br /><br />
+
+Ut id leo sed tortor porttitor tincidunt. In nec felis. Maecenas tempus nunc et tortor. Fusce arcu. Mauris at leo. Nunc ultricies augue a quam. Duis quis mi sed leo hendrerit hendrerit. Vestibulum eros. Nam felis. Donec felis. Suspendisse egestas dictum augue. Suspendisse nec ligula non ipsum fermentum tempus. In velit felis, lobortis nec, porttitor nec, rutrum at, leo. Donec porta eleifend felis. Nunc ullamcorper est porta purus porttitor volutpat. Sed pharetra ligula et nisi. Donec vehicula sodales eros. Cras ut sem tincidunt turpis dignissim sollicitudin. Aliquam quis tellus.<br /><br />
+
+Cras id arcu quis neque mollis laoreet. Nulla mattis. Pellentesque et lectus. Praesent id sem. Proin malesuada nunc quis est. Integer varius sodales purus. Ut tellus. Vestibulum sed sem rhoncus justo eleifend feugiat. Donec nisi massa, sagittis non, fringilla sed, adipiscing at, diam. Donec pellentesque orci facilisis nisi. Sed a leo id odio cursus dictum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eu augue. Quisque consequat. Cras odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean a nunc ac magna viverra pharetra. Donec at dolor. Nulla aliquet venenatis magna.<br /><br />
+
+Vivamus tortor dolor, feugiat quis, aliquet eu, commodo at, felis. Vivamus venenatis nibh ac nunc. Pellentesque euismod. Duis arcu. Mauris nec metus vitae augue varius euismod. Mauris tellus. Quisque tristique euismod lacus. Proin eu quam vitae ipsum elementum tincidunt. Ut rutrum ultrices enim. Quisque fringilla pede quis ante pharetra fermentum. Nunc gravida. In augue massa, congue non, cursus quis, interdum vel, nisl. Pellentesque tempus, purus vel ornare semper, justo nibh consequat tortor, ac facilisis turpis nisi ut lorem. Duis sapien.<br /><br />
+
+In hac habitasse platea dictumst. Sed egestas rhoncus dolor. Proin turpis nibh, mollis a, egestas ut, faucibus aliquet, est. Sed quam justo, lobortis vel, lacinia sed, ultrices ultricies, massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi bibendum diam nec massa. Morbi auctor. Fusce condimentum volutpat ante. Proin sed arcu in dui sollicitudin imperdiet. Donec feugiat faucibus diam. In auctor. Nunc tincidunt pellentesque massa. Maecenas nulla. Nam sapien neque, pretium sed, pulvinar vel, posuere nec, nibh. Vivamus sagittis, nunc eu placerat fringilla, ligula velit bibendum urna, molestie commodo magna magna nec lacus. Aenean vitae quam.<br /><br />
+
+Aenean non dui. Aliquam rutrum tempor est. Cras fringilla lacus vitae sem. Suspendisse laoreet sodales magna. Curabitur posuere mi at magna. Ut fermentum, dui quis posuere sagittis, erat lorem feugiat nibh, a suscipit metus nulla vitae tellus. In eget velit. Nam iaculis dictum diam. Sed porttitor metus at nunc. Fusce quis pede adipiscing risus congue mollis. Ut dictum, mi at accumsan venenatis, orci nulla accumsan sem, ut aliquam felis libero quis quam. Nulla turpis diam, tempus ut, dictum sit amet, blandit sit amet, enim. Suspendisse potenti. Maecenas elit turpis, malesuada et, ultricies quis, congue et, enim. Maecenas ut sapien. Nullam hendrerit accumsan tellus.<br /><br />
+
+Proin cursus orci eu dolor. Suspendisse sem magna, porta ac, feugiat in, pretium sed, felis. Nulla elementum commodo massa. Suspendisse consectetuer nibh in urna. Sed sit amet augue. Nam id ligula. Phasellus ullamcorper tellus ut eros. Vivamus arcu lectus, molestie at, posuere non, suscipit semper, eros. Donec sed augue a tellus tincidunt vulputate. Nullam elementum ante quis augue. Cras mauris felis, elementum sit amet, iaculis vitae, ornare nec, nisl. Nam venenatis orci et leo. Nam scelerisque. Praesent tellus diam, vehicula et, volutpat at, sollicitudin aliquet, dui. Phasellus tellus velit, malesuada id, semper ac, venenatis sit amet, nibh. Duis convallis lorem a erat.<br /><br />
+
+Pellentesque tincidunt eleifend ligula. Aenean turpis justo, ornare in, mattis sit amet, eleifend ac, odio. Maecenas nec metus vitae velit eleifend pretium. Donec dui orci, tempus sed, malesuada tempor, dignissim et, ante. Fusce egestas, dolor mollis faucibus sollicitudin, nisl felis porta libero, eget varius justo libero id mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi auctor gravida massa. Nullam sed elit. Nullam pulvinar. In dignissim cursus purus. Phasellus non ante sed turpis venenatis dignissim. Nam libero pede, laoreet sed, vulputate quis, egestas ac, risus.<br /><br />
+
+Vivamus sagittis facilisis libero. Pellentesque velit erat, ornare a, consectetuer et, congue sed, pede. Nullam justo massa, volutpat et, blandit ut, pharetra vel, leo. Aliquam rutrum. Vestibulum blandit varius ipsum. Nullam vel velit. In non lectus ut sem consectetuer luctus. Ut feugiat massa vel nibh. Sed vitae turpis vitae eros pharetra posuere. Sed non neque. Ut auctor odio a quam eleifend vestibulum. Maecenas tincidunt risus vel ipsum. Morbi euismod cursus turpis. Nam quis dolor non libero facilisis lacinia. Pellentesque ultrices. Aenean ullamcorper, purus at sollicitudin imperdiet, urna augue bibendum ligula, eget placerat diam mi a mauris. Donec porttitor varius augue.<br /><br />
+
+Pellentesque fringilla erat in ante. Pellentesque orci tellus, varius vitae, tempus sed, vehicula placerat, dolor. Praesent nisi diam, pharetra nec, laoreet tempor, elementum in, tortor. In accumsan. Fusce ut mi ac ligula venenatis sollicitudin. Donec vulputate mollis nisl. Aenean nec purus nec lorem dapibus semper. In at enim nec orci consequat imperdiet. Curabitur vestibulum sapien id tellus. Phasellus iaculis lectus. Ut non turpis. Donec vitae ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum eget erat eu massa laoreet vestibulum. Donec convallis erat eu ipsum. Donec libero massa, lacinia nec, mollis eu, tempus a, enim. Cras eu leo. Sed massa nunc, scelerisque sit amet, faucibus quis, blandit in, nunc. Aliquam posuere enim nec nibh. Duis quis velit tempor eros interdum interdum.<br /><br />
+
+Aenean tempus, leo at vehicula varius, lectus elit facilisis tellus, sit amet ornare metus metus ut metus. In eros. Aenean eget est. Curabitur egestas. Sed ut elit. Mauris iaculis accumsan ligula. Aliquam imperdiet, libero et iaculis semper, mi augue posuere velit, id pretium nunc justo nec enim. Mauris lobortis turpis sit amet lacus. Quisque eu risus eget nibh mollis tristique. Mauris vestibulum. Etiam dui massa, condimentum a, tempus et, convallis vulputate, ante. Curabitur porta ultricies tortor. Praesent rutrum volutpat ipsum. In accumsan vestibulum lacus.<br /><br />
+
+Ut in justo vel enim viverra euismod. Phasellus ultrices semper urna. Aenean mauris tellus, vulputate feugiat, cursus ac, dignissim vel, nulla. In hac habitasse platea dictumst. In euismod, risus et pellentesque vulputate, nibh est sollicitudin felis, in accumsan diam metus sit amet diam. Fusce turpis lectus, ultricies euismod, pellentesque non, ullamcorper in, nunc. Vestibulum accumsan, lorem nec malesuada adipiscing, ante augue pellentesque magna, quis laoreet neque eros vel sapien. Phasellus feugiat. Curabitur gravida mauris eget augue. Praesent bibendum. Aenean sit amet odio ut arcu pellentesque scelerisque. Donec luctus venenatis eros. Phasellus tempus enim nec tortor. Sed ac lorem. Proin ut dui. Aliquam ipsum.<br /><br />
+
+Nunc varius dui sit amet tellus tincidunt facilisis. Mauris molestie varius purus. Vivamus gravida, est sed auctor tincidunt, risus justo euismod tortor, sed rhoncus nunc ipsum ac turpis. Nullam lacus sapien, ornare nec, placerat quis, commodo sit amet, ante. Etiam non urna vitae ligula hendrerit pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Integer feugiat, mi non egestas suscipit, pede sapien mattis pede, et tristique dui risus posuere erat. Nulla nunc odio, consequat feugiat, fermentum in, dignissim id, dolor. Donec rutrum purus sit amet dolor. Vestibulum molestie. Nulla pulvinar, mi ac eleifend cursus, pede eros ultrices sapien, sed consequat est mi eget mauris. Sed nibh metus, luctus vitae, volutpat sit amet, consectetuer nec, neque. Mauris rutrum dapibus nunc. Ut iaculis turpis at mauris. In hac habitasse platea dictumst. Sed congue fringilla orci. Sed turpis pede, vehicula sed, imperdiet ac, porttitor vestibulum, metus. Nunc cursus. Nam turpis ipsum, ultricies nec, cursus sit amet, rhoncus molestie, mi.<br /><br />
+
+Suspendisse potenti. Donec massa ante, porttitor id, ornare vel, rutrum sed, mauris. Donec auctor risus non elit. Donec pretium congue elit. Aliquam varius. Aliquam eget lacus. Vestibulum sed mauris eu erat ornare adipiscing. Proin congue. Nulla facilisi. Sed orci libero, tincidunt id, mattis non, volutpat in, ligula. Fusce ut odio. Aliquam semper eleifend felis. Nunc orci. Nulla facilisi.<br /><br />
+
+Morbi dolor nisi, pulvinar ut, feugiat at, rutrum nec, lectus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc gravida, libero a pulvinar iaculis, mi nulla adipiscing quam, ut gravida quam nunc quis nibh. Mauris ac nunc ut sem aliquet rhoncus. Vivamus urna. Nulla semper. Vivamus laoreet. Sed scelerisque condimentum dui. Phasellus libero metus, iaculis vel, elementum vel, scelerisque mattis, dui. In hac habitasse platea dictumst. Pellentesque ac nisi. Integer gravida. Praesent pharetra sem vitae justo. Praesent tempor nulla eget metus. Cras at dui. Nulla ultrices sem. Nam facilisis lectus malesuada orci. Vestibulum porttitor, neque ut tristique aliquet, dui libero venenatis augue, ac convallis nibh sem ac orci. Suspendisse potenti. Mauris suscipit dapibus mauris.<br /><br />
+
+Morbi sapien. Integer leo erat, blandit at, convallis eget, luctus eu, arcu. Sed urna metus, dignissim pulvinar, viverra sed, lacinia at, mi. Mauris congue feugiat mi. Mauris libero urna, blandit non, fermentum non, semper eu, erat. Pellentesque nec lacus. Fusce ut elit. Fusce sagittis, magna vel luctus suscipit, est ligula imperdiet leo, vulputate porta nisl sem ut erat. Vestibulum arcu turpis, tincidunt in, faucibus quis, pharetra at, elit. Vivamus imperdiet magna sit amet neque. Vestibulum vel leo. Suspendisse semper congue magna. Donec eleifend rhoncus lacus. Morbi tellus nunc, hendrerit sit amet, fringilla at, commodo vitae, sem. Maecenas vestibulum eros sagittis ipsum. Curabitur elit felis, rutrum vel, viverra vitae, vulputate et, arcu.<br /><br />
+
+Quisque ac augue quis tellus dictum ornare. Quisque vitae orci eu mi cursus feugiat. Nulla facilisi. In dui magna, ultricies eget, tempor sed, malesuada in, sapien. Duis mi. In hac habitasse platea dictumst. Nunc ultricies. Nulla accumsan, libero sed ullamcorper porttitor, eros lectus aliquam erat, in aliquet massa metus ac purus. Pellentesque enim odio, facilisis sed, sagittis vitae, scelerisque id, arcu. Aenean ante lectus, cursus non, rutrum vel, faucibus porta, tortor. Nam vitae neque. Morbi non turpis. Etiam facilisis. Mauris et urna. Cras tempor. Nullam rutrum, nisl eu cursus tristique, velit tellus aliquam pede, quis interdum massa sem id lorem. Fusce posuere. Quisque in leo venenatis dui facilisis sodales. In orci augue, bibendum et, viverra id, vehicula vitae, augue.<br /><br />
+
+Etiam malesuada est vel dolor. Integer suscipit volutpat libero. Cras semper dui sit amet dui. Quisque imperdiet leo vitae felis. Morbi volutpat nisi. Vestibulum sit amet eros a odio pellentesque lobortis. Sed dapibus est quis ante. Ut lobortis. Maecenas ullamcorper libero vel lacus. Aenean ut turpis vel elit tempor congue. Morbi sed sem. Aliquam odio neque, cursus sit amet, sollicitudin eu, vestibulum ac, turpis. Donec sed mauris. Pellentesque ut enim a sem lobortis euismod. Ut tellus odio, dapibus sed, iaculis sed, congue vel, massa. Phasellus tempus orci non orci. Proin erat ante, ornare ac, ornare commodo, elementum sit amet, libero. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquam ornare dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras quis ante et felis porta porttitor. Aliquam erat volutpat. Phasellus et lacus. Morbi augue augue, sollicitudin at, tristique eget, porta vel, neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Mauris id velit a erat molestie venenatis. Cras pellentesque. Maecenas tincidunt sem ut odio. Proin at ante. Cras fringilla, erat ac varius dapibus, lacus dui posuere mauris, at interdum lacus nisi ac pede.<br /><br />
+
+Pellentesque tristique. Donec eleifend. Nam tempus, mauris eu fermentum scelerisque, mauris nisl gravida nisl, sit amet pulvinar magna neque eget sapien. Etiam eu diam eu enim commodo scelerisque. Suspendisse potenti. Sed vitae sapien. Proin vel dui in augue tempus facilisis. Aenean nibh erat, interdum id, dictum ac, pharetra ac, eros. Suspendisse magna. Sed aliquet tellus non leo. Curabitur velit. Suspendisse sapien leo, pretium a, vehicula vel, faucibus nec, mi. Maecenas tincidunt volutpat diam. Proin vitae quam at dui gravida placerat. Sed eu nulla. Integer iaculis massa ac lacus. Praesent auctor ultricies quam. Suspendisse ut sapien. Morbi varius quam vel nisl.<br /><br />
+
+Nulla facilisi. Donec lobortis urna at mi. Mauris vulputate, enim sed auctor molestie, nisi elit vehicula mi, ac sollicitudin felis turpis nec ante. Praesent rutrum, arcu non semper euismod, magna sapien rutrum elit, eu varius turpis erat at eros. Morbi porta malesuada massa. Etiam fermentum, urna non sagittis gravida, lacus ligula blandit massa, vel scelerisque nunc odio vitae turpis. Morbi et leo. Pellentesque a neque nec nibh rhoncus ultricies. Curabitur hendrerit velit non velit. Sed mattis lacus vel urna. Integer ultricies sem non elit consequat consequat.<br /><br />
+
+Fusce imperdiet. Etiam semper vulputate est. Aenean posuere, velit dapibus dapibus vehicula, magna ante laoreet mauris, quis tempus neque nunc quis ligula. Nulla fringilla dignissim leo. Nulla laoreet libero ut urna. Nunc bibendum lorem vitae diam. Duis mi. Phasellus vitae diam. Morbi quis urna. Pellentesque rutrum est et magna. Integer pharetra. Phasellus ante velit, consectetuer sed, volutpat auctor, varius eu, enim. Maecenas fringilla odio et dui. Quisque tempus, est non cursus lacinia, turpis massa consequat purus, a pellentesque sem felis sed augue.<br /><br />
+
+Pellentesque semper rhoncus odio. Ut at libero. Praesent molestie. Cras odio dui, vulputate quis, ultrices in, pellentesque et, ipsum. Nunc fermentum. Nulla et purus. Sed libero nisl, tempor a, posuere nec, accumsan ut, urna. Praesent facilisis lobortis lectus. Curabitur viverra feugiat turpis. Curabitur ante magna, vulputate sodales, hendrerit nec, interdum in, odio. Vivamus accumsan felis eleifend massa. Suspendisse pharetra.<br /><br />
+
+Suspendisse at odio ac lorem hendrerit luctus. In dolor nibh, sodales quis, consectetuer id, mattis ut, arcu. Nullam diam nisl, congue vel, bibendum sit amet, fringilla sed, tortor. Praesent mattis dui non nibh. Donec ipsum nulla, tempor in, pellentesque nec, auctor ut, risus. Praesent metus lacus, mattis vel, varius et, feugiat vitae, metus. Donec nec leo. Ut velit nibh, porta id, tempus in, mattis ac, lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse sed felis. Pellentesque luctus. Vivamus elit. In ultricies lacinia ipsum. Pellentesque venenatis ante eget tortor. Duis lacus. Nulla pretium libero nec nunc. Sed pede.<br /><br />
+
+Fusce ligula. Cras dui enim, tincidunt nec, ultricies sit amet, vehicula vitae, orci. Cras nec erat. Praesent non nulla. Proin commodo hendrerit quam. Aliquam sed massa ut elit venenatis hendrerit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porttitor ante ac nisl fringilla sollicitudin. Quisque nec nibh et nunc gravida posuere. Sed eget libero ut eros faucibus ultricies. Vivamus gravida augue sit amet leo suscipit tempor. Maecenas elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec condimentum diam non elit. In porttitor consectetuer nisi. Praesent vitae nulla et eros porttitor ornare. Quisque eu purus quis pede suscipit elementum. Proin tempor tincidunt tortor. Etiam tellus.<br /><br />
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce cursus. Mauris non leo. Pellentesque ullamcorper justo in lectus. Cras ut purus eu enim consectetuer rhoncus. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In placerat pellentesque arcu. Sed volutpat, lectus sed ullamcorper adipiscing, nunc nisl molestie orci, ac commodo nunc metus congue urna. Aliquam tortor nunc, tristique eget, bibendum eu, pharetra id, massa. Nunc non tellus. Pellentesque venenatis. Nunc consequat, urna at pellentesque blandit, ante orci consectetuer metus, eu fringilla arcu turpis in lacus. Mauris rhoncus risus nec massa. Proin rhoncus facilisis ligula. Quisque imperdiet porta nisl.<br /><br />
+
+Sed quis risus eget sem consectetuer pretium. Maecenas et erat ac lorem fermentum fermentum. Nulla elementum. Fusce semper tincidunt ipsum. Donec interdum mauris ac nibh. Nulla eget purus. Donec convallis, lorem nec tincidunt viverra, quam purus malesuada orci, nec gravida purus risus vel diam. Nullam quis tortor. Fusce eget tellus. Sed cursus lorem. Etiam ornare rhoncus augue. Nullam auctor pede et lacus.<br /><br />
+
+Nullam pellentesque condimentum ligula. Donec ullamcorper, enim a fringilla elementum, ante lacus malesuada risus, vitae vulputate dolor tellus in nisl. Pellentesque diam eros, tempor pharetra, suscipit vel, tincidunt et, dui. Aenean augue tortor, semper aliquam, euismod eu, posuere id, ante. Aenean consequat. Ut turpis pede, auctor eget, mollis vitae, euismod id, leo. Phasellus urna. Sed rutrum, eros sed porta placerat, nisl mauris auctor lorem, quis ultricies metus sapien eget nulla. Phasellus quis nisi sed dolor fermentum dictum. Ut pretium pede quis sapien. In hac habitasse platea dictumst. Suspendisse volutpat, urna ac pretium malesuada, risus ligula dictum ligula, vel fringilla diam metus et nisl. Mauris at massa at ante venenatis vehicula. Proin rhoncus dui nec nibh. Sed vel felis ornare erat bibendum mattis.<br /><br />
+
+Nunc iaculis venenatis nisl. Mauris faucibus imperdiet nibh. Donec tristique mattis lectus. Aliquam erat volutpat. Donec et mauris a pede cursus lobortis. Pellentesque dictum malesuada augue. Pellentesque malesuada, lorem et fringilla posuere, libero nulla cursus pede, eget adipiscing nisl magna id diam. Morbi tortor. Ut et urna. Duis quis massa.<br /><br />
+
+Quisque eu eros ut tortor dapibus auctor. Pellentesque commodo tellus vitae tortor. Praesent accumsan auctor ligula. Vestibulum convallis molestie justo. Praesent et ipsum. Vestibulum neque quam, ornare eu, cursus at, sollicitudin eget, nulla. Fusce leo massa, euismod cursus, scelerisque nec, mollis nec, est. Morbi iaculis tempor risus. In hac habitasse platea dictumst. Pellentesque malesuada libero. Nulla facilisi. Nam ante. Maecenas tincidunt eros ut justo. Morbi sollicitudin pulvinar elit. Aenean nisl.<br /><br />
+
+Morbi dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce at lectus. Cras vulputate. Duis velit sapien, vehicula ut, consectetuer nec, pretium in, metus. Praesent quis mi. Fusce rhoncus enim nec nibh. Suspendisse dictum nunc. Duis ut metus sed est tempor semper. Nullam elit dolor, facilisis nec, gravida in, dictum sed, sapien. In laoreet. Sed quis nulla id mi mollis congue. Ut ante massa, commodo nec, ornare quis, blandit at, elit. In hac habitasse platea dictumst. Mauris neque nisi, porta non, eleifend fringilla, scelerisque porta, urna. Proin euismod cursus erat. Etiam non lorem et ipsum volutpat posuere. Donec ante justo, fringilla at, fermentum quis, sagittis nec, ante.<br /><br />
+
+Proin lobortis. Sed a tellus ut nulla vestibulum gravida. Suspendisse potenti. Fusce at nisi. Ut risus. Duis velit. In hac habitasse platea dictumst. Suspendisse augue eros, condimentum sit amet, vulputate id, volutpat in, orci. Praesent tempor, pede eu fermentum pharetra, ante metus pretium velit, accumsan varius risus erat vitae enim. Nullam sapien dui, malesuada sit amet, hendrerit eget, viverra sed, augue. Vivamus vulputate justo sed metus. Proin lacus. Cras erat augue, adipiscing nec, semper fermentum, varius id, urna. Quisque mi nunc, fringilla ut, pellentesque in, commodo sit amet, urna. Nunc luctus.<br /><br />
+
+Maecenas elementum eros ac justo. Proin felis. Duis pretium sagittis nisi. Praesent ac nulla. Nullam dui tellus, vestibulum nec, condimentum nec, dapibus in, mauris. Duis felis. Mauris sodales, nibh at viverra eleifend, libero ante hendrerit enim, non congue massa dolor sit amet orci. Sed urna leo, ullamcorper a, luctus ut, tincidunt at, ipsum. Duis placerat ullamcorper sapien. Cras a quam eget libero venenatis viverra.<br /><br />
+
+Curabitur hendrerit blandit massa. Suspendisse ligula urna, aliquet sit amet, accumsan in, porttitor nec, dolor. Praesent sodales orci vitae diam. Ut convallis ipsum egestas ligula. Aenean feugiat pede sit amet nulla. Suspendisse enim ante, porta eu, imperdiet in, congue nec, enim. Phasellus vitae velit nec risus hendrerit pharetra. Suspendisse potenti. Donec rutrum ultricies diam. Nulla nisl. Etiam justo enim, bibendum sit amet, mollis ac, fringilla ut, nunc. Proin euismod pede vitae ligula. Proin ante eros, commodo eu, ultrices eu, sagittis sed, nisi. Nullam et leo. Fusce consectetuer orci eget odio. Maecenas accumsan posuere mauris. Maecenas adipiscing. Nulla ut tellus at ante tristique vulputate. Fusce erat.<br /><br />
+
+Donec quis orci non nulla consectetuer placerat. Aliquam tincidunt auctor lacus. Fusce nisi metus, mattis id, mollis eget, laoreet vel, dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean faucibus mollis nibh. Fusce dapibus leo. Ut lacinia elit in turpis. Vivamus sapien sem, imperdiet eu, facilisis ut, blandit quis, purus. Vivamus urna. Vivamus non nibh sed erat ultricies sodales. Maecenas molestie sem ac pede. Etiam consequat commodo sem.<br /><br />
+
+Sed vitae metus et lacus euismod malesuada. Maecenas bibendum nunc at dui. Maecenas luctus, turpis nec tincidunt convallis, arcu nisi gravida diam, vitae imperdiet mi nisl a odio. Integer vitae massa non magna ultrices ullamcorper. Morbi quis ligula in purus gravida ultrices. Nunc varius posuere diam. Mauris eget ante. Maecenas nunc. Quisque quam metus, vulputate a, tristique non, malesuada nec, pede. Sed interdum consectetuer urna. Vivamus tincidunt libero vitae nulla. Pellentesque lobortis eleifend magna. Duis vehicula gravida lorem. Vivamus tortor massa, varius ut, gravida euismod, posuere faucibus, eros. Etiam aliquam, quam sed pretium lacinia, nulla mi auctor ante, et porttitor lorem nulla vitae enim. Donec justo. Maecenas lorem. Pellentesque faucibus dapibus eros. Vivamus mollis leo id neque fringilla elementum. Phasellus convallis scelerisque ipsum.<br /><br />
+
+Sed sapien dui, pharetra a, fringilla interdum, vestibulum nec, tellus. Suspendisse ultrices diam quis lectus. Nulla neque felis, tincidunt vitae, suscipit at, gravida euismod, felis. Sed elementum eros eu nisl. Pellentesque imperdiet. Donec vehicula. Duis eu purus molestie diam volutpat lacinia. Phasellus ultricies pharetra pede. Suspendisse varius leo non dui. Aliquam erat volutpat. Nam nisi. Vivamus pellentesque congue eros. Integer risus. Nullam lectus. Sed vel sapien. Praesent blandit neque eu enim.<br /><br />
+
+Nunc dictum venenatis velit. Ut aliquam velit. In dapibus, nisl vel elementum auctor, erat metus elementum ligula, vel molestie lectus nulla nec nulla. Sed tempus elit eget diam. Suspendisse potenti. Mauris tempus ante eu magna. Suspendisse potenti. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut iaculis tristique pede. Cras vel mauris sed mi accumsan blandit. Nulla vel tortor. Etiam lacinia. Suspendisse eget lectus sed nisl sodales ultricies. Aliquam venenatis ante quis tortor. Fusce a lorem.<br /><br />
+
+Mauris euismod sagittis urna. Pellentesque pulvinar tellus id libero. Morbi id magna ut libero vehicula sodales. Nulla pretium. Sed mauris leo, scelerisque a, varius a, commodo convallis, erat. In tellus. Suspendisse velit felis, sodales non, lacinia quis, iaculis eu, tortor. Nunc pellentesque. In iaculis est a mi viverra tincidunt. Etiam eleifend mi a ante. Nullam et risus. Etiam tempor enim id nunc vehicula vestibulum. Pellentesque mollis, felis eu laoreet feugiat, tortor enim convallis eros, non mollis justo ipsum et sem. Cras egestas massa. Sed molestie, turpis ac imperdiet tristique, turpis arcu rhoncus elit, vitae imperdiet enim massa at lorem. Donec aliquam laoreet nunc.<br /><br />
+
+Cras arcu justo, fringilla sit amet, ultricies eu, condimentum gravida, urna. In erat. Vivamus rhoncus ipsum quis quam. In eu tortor et eros accumsan malesuada. Curabitur hendrerit quam et risus ultrices porta. Maecenas pulvinar turpis vel arcu. Cras erat. Mauris tempus. Nunc a risus id nulla ultricies ullamcorper. Aenean nec mi ut dolor elementum iaculis. Sed nisi. Donec nisl lectus, condimentum nec, commodo ac, imperdiet id, nibh. Morbi ante sapien, laoreet eget, auctor et, tempus nec, elit. Aliquam luctus est eu elit.<br /><br />
+
+Sed malesuada interdum purus. Aenean id odio sed dolor sagittis porttitor. Sed nec ipsum. Nullam porttitor nunc sit amet leo. Praesent condimentum sapien quis tortor. Sed dapibus ipsum id risus. Fusce dapibus fringilla nunc. Cras tristique mauris sit amet diam. Suspendisse molestie, nisl ut scelerisque pharetra, lorem leo rutrum quam, in vestibulum felis nulla vitae sapien. Integer elementum velit quis eros adipiscing scelerisque. Etiam ac purus sit amet est laoreet porttitor. Etiam gravida pretium felis. Aenean sapien. Sed est tellus, hendrerit pellentesque, imperdiet sed, tempus at, dolor. Integer feugiat lectus vulputate metus. Mauris at neque.<br /><br />
+
+Nunc nec orci in dui aliquet placerat. Aenean ultrices diam quis nisl. Phasellus tempor lorem sed orci. Nam mauris erat, congue ac, condimentum quis, accumsan eget, lectus. Cras vulputate pulvinar lorem. Proin non mi ac orci gravida gravida. Fusce urna. Proin suscipit dui ultrices justo. Nullam pretium nibh quis dui. Cras sem magna, lacinia sit amet, laoreet id, pretium sed, nisi. Suspendisse et pede bibendum erat porttitor blandit. Vestibulum condimentum nisi pellentesque eros.<br /><br />
+
+Proin tellus. Pellentesque eu nulla ut lorem dictum tincidunt. Duis non enim. Sed ornare magna dignissim lectus. Curabitur ligula. Maecenas varius. Pellentesque condimentum bibendum diam. Ut sed nibh ut libero consectetuer rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer ligula. Etiam accumsan. Ut vestibulum auctor mi. In hac habitasse platea dictumst. Nunc mollis. Aenean velit metus, auctor ac, lacinia sit amet, facilisis sed, risus. Nam aliquam volutpat elit. Quisque quis diam sed felis mollis feugiat. Aliquam luctus. Donec nec magna.<br /><br />
+
+Morbi porttitor viverra tellus. Duis elit lectus, convallis nec, rutrum nec, accumsan vel, tellus. Duis venenatis nisl in velit. Donec mauris. Morbi a diam at felis molestie dignissim. Praesent consectetuer leo sed tortor. Aliquam volutpat, eros vitae facilisis rhoncus, nibh massa sagittis magna, sed placerat metus turpis a ligula. Proin at purus ut erat feugiat consequat. Nam ornare libero nec turpis. Aenean eget quam vitae diam convallis faucibus. Duis molestie turpis vel lacus semper convallis.<br /><br />
+
+Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed tempus turpis eget quam fringilla fermentum. Curabitur risus magna, congue vel, commodo sed, tempus sit amet, lacus. Curabitur quam nulla, bibendum in, hendrerit eu, ultricies vitae, ligula. Curabitur nisl. Mauris nulla justo, laoreet non, faucibus sit amet, vulputate sit amet, lectus. Maecenas pharetra ligula quis nisl. Suspendisse suscipit tortor ac eros. Ut non urna tincidunt sapien aliquet consectetuer. Etiam convallis. Proin tempor tellus et dui. Donec sit amet lorem. Etiam et eros id nisl fermentum varius. Aenean ultricies. Donec leo. Vivamus adipiscing tempus dolor.<br /><br />
+
+Vestibulum convallis venenatis quam. Quisque sed ante. Pellentesque auctor ipsum sed mi. Integer gravida. Sed molestie nisi tempus quam. In varius. Curabitur feugiat, erat sed imperdiet interdum, ante justo convallis diam, at condimentum nunc odio a nulla. Nam turpis enim, sodales at, cursus varius, volutpat sed, risus. Nunc malesuada suscipit dui. Donec tincidunt molestie diam. Phasellus mattis congue neque. Maecenas in lorem. Maecenas ultricies rhoncus arcu. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce varius purus in nibh.<br /><br />
+
+Curabitur lobortis mi fermentum nisi. Donec sed augue at nisl euismod interdum. Nam ultrices mi sit amet quam. Quisque luctus sem id lorem. Phasellus mattis neque id arcu. Aliquam pellentesque iaculis mi. Ut at libero ut felis iaculis dapibus. Proin mauris. Etiam vel orci nec magna vehicula lacinia. Vivamus eu nulla. Aenean vehicula, nunc ac cursus dictum, elit odio tempor mauris, ultrices porta ligula erat ac nibh. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc ac nibh placerat massa dapibus lobortis. Maecenas et mi. Etiam vel ipsum. Nam nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec laoreet massa egestas lectus. Maecenas dictum. Integer at purus.<br /><br />
+
+Phasellus nisi. Duis ullamcorper justo in est. Suspendisse potenti. Nunc velit est, ultricies eu, facilisis sed, condimentum ut, ligula. Phasellus a metus. Fusce ac elit adipiscing justo tincidunt varius. Quisque pede. Nulla porta ante eget nunc. Pellentesque viverra. Nunc eleifend. Nulla facilisi. Mauris molestie est a arcu. Pellentesque aliquam, sapien id tincidunt feugiat, lectus massa porttitor pede, id accumsan ipsum nisi vel ligula. Integer eu enim et dui suscipit varius.<br /><br />
+
+Aliquam a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Phasellus rhoncus posuere nisi. Integer et tellus in odio ultrices euismod. Vestibulum facilisis placerat nisl. Fusce sed lectus. Aenean semper enim. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec congue tortor accumsan erat. Pellentesque diam erat, congue congue, tristique ac, auctor a, sem. Donec feugiat leo id augue.<br /><br />
+
+Sed tempor est non augue. Suspendisse pretium fermentum erat. Quisque dapibus tellus vitae sapien. Vivamus feugiat libero non nunc. Phasellus ornare aliquet arcu. Sed faucibus. Phasellus hendrerit tortor vitae elit pellentesque malesuada. Donec eu tortor quis lacus fermentum congue. Pellentesque adipiscing risus at felis. Quisque est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales nisl non pede. Etiam ac libero. Morbi euismod libero faucibus velit dignissim tempor.<br /><br />
+
+Nam tempor, velit in condimentum bibendum, arcu elit adipiscing sapien, vitae adipiscing enim lectus nec tortor. Aliquam varius egestas arcu. Duis nisl libero, commodo egestas, ultrices sed, convallis non, lectus. Proin semper. Donec pretium. In bibendum luctus metus. Quisque et tortor. Sed ultricies. Sed libero. Phasellus vel lacus at eros pretium dignissim. Phasellus risus nisi, sodales at, ultricies eleifend, laoreet in, neque. Suspendisse accumsan gravida lectus. Donec sed nulla. Pellentesque lobortis lorem at felis. Morbi ultricies volutpat turpis.<br /><br />
+
+Donec nisl risus, vulputate ac, congue consequat, aliquam et, dolor. Proin accumsan lorem in augue. Donec non nisi. Ut blandit, ligula ut sagittis aliquam, felis dolor sodales odio, sit amet accumsan augue tortor vitae nulla. Nunc sit amet arcu id sapien mollis gravida. Etiam luctus dolor quis sem. Nullam in metus sed massa tincidunt porttitor. Phasellus odio nulla, ullamcorper quis, ornare non, pretium sed, dui. Quisque tincidunt. Proin diam sapien, imperdiet quis, scelerisque nec, scelerisque non, sapien. Nulla facilisi.<br /><br />
+
+Donec tempor dolor sit amet elit. Maecenas nec ipsum eu quam consectetuer sodales. Duis imperdiet ante ac tellus. Vestibulum blandit porta ipsum. Aenean purus justo, mollis eu, consectetuer vel, sodales sollicitudin, leo. Mauris sollicitudin ullamcorper odio. Maecenas metus turpis, fringilla nec, tincidunt sed, pellentesque ut, libero. Suspendisse bibendum. Phasellus risus nibh, luctus ac, sagittis in, sagittis a, libero. Etiam fringilla, dui tristique fringilla sollicitudin, urna odio malesuada sapien, ut dictum augue lorem ac eros. Phasellus lobortis neque eget ipsum. Proin neque ipsum, posuere in, semper eu, tempor eu, leo.<br /><br />
+
+Pellentesque ante nulla, sodales in, euismod vel, eleifend vitae, turpis. Sed nunc. Sed eleifend elit non ipsum. Quisque posuere sapien vel metus. Nullam euismod eleifend nunc. Vestibulum ligula urna, posuere sit amet, posuere ac, rutrum id, libero. Mauris lorem metus, porta at, elementum quis, tempor ut, nibh. Aenean porttitor magna quis odio. Praesent pulvinar varius leo. Maecenas vitae risus tristique mauris imperdiet congue. Duis ullamcorper venenatis velit. Phasellus eleifend. Maecenas nec velit. Aliquam eget turpis. Cras iaculis volutpat nulla. Donec luctus, diam eu varius convallis, diam justo venenatis erat, convallis mattis mauris mauris vitae lacus. Pellentesque id leo. Donec at massa vitae mi bibendum vehicula. Proin placerat.<br /><br />
+
+Mauris convallis dui sit amet enim. Nullam dui. Integer convallis. Nunc ac sapien. Curabitur et felis. Sed velit odio, porta vitae, malesuada sed, convallis sed, turpis. Praesent eget magna. Maecenas at risus. Curabitur dictum. Maecenas ligula lectus, viverra ut, pulvinar sed, pulvinar at, diam. Suspendisse bibendum urna id odio. Mauris adipiscing. Donec accumsan lorem nec nunc. Sed commodo.<br /><br />
+
+Nulla facilisi. Morbi eget mauris sit amet augue varius imperdiet. Donec viverra erat eget metus. Proin pharetra condimentum quam. Nunc vel odio. Mauris elementum augue nec metus. Vivamus quam. Donec nec quam. Integer lacus odio, placerat sed, tempus nec, bibendum in, justo. Nulla aliquam, neque vel sagittis adipiscing, lectus massa gravida quam, ut pulvinar tellus massa lobortis massa.<br /><br />
+
+Curabitur vitae nisi et lectus porttitor euismod. Morbi ultricies convallis nunc. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla lobortis faucibus nulla. Maecenas pharetra turpis commodo dolor. Donec dolor neque, consectetuer non, dignissim at, blandit ultricies, felis. Nunc quis justo. Maecenas faucibus. Sed eget purus. Aenean dui eros, luctus a, rhoncus non, vestibulum bibendum, pede. Proin imperdiet sollicitudin sem.<br /><br />
+
+Suspendisse nisi nisl, commodo a, aliquam ut, commodo bibendum, neque. Donec blandit. Mauris tortor. Proin lectus ipsum, venenatis non, auctor vel, interdum vel, lacus. Nullam tempor ipsum a enim. Duis elit elit, cursus vel, venenatis in, dignissim vitae, neque. Morbi erat. Proin rutrum hendrerit massa. Pellentesque ultrices, ligula eu molestie auctor, tellus elit rhoncus turpis, at aliquet ante pede id ipsum. Aenean vitae est. Aliquam non neque. Ut nunc. Nulla at elit eu nunc molestie suscipit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent nec ipsum. Vivamus elit arcu, faucibus non, pulvinar vel, vehicula et, massa. Aenean non sapien vitae sapien porttitor pretium. Sed vestibulum, lorem id venenatis hendrerit, mi nunc gravida ligula, sed euismod justo felis sit amet dolor. Duis molestie, nunc mattis feugiat accumsan, nibh est posuere nibh, volutpat consectetuer risus eros eget lectus.<br /><br />
+
+Vivamus non mauris. Nullam ornare convallis magna. In congue feugiat velit. Proin tellus magna, congue eu, scelerisque ut, hendrerit ac, lorem. Suspendisse potenti. Sed rhoncus, nunc sed tempus venenatis, eros dolor ultricies felis, nec tincidunt pede sem eget orci. Sed consequat leo. In porta turpis eget nibh. Aliquam sem tortor, gravida eu, fermentum vulputate, vestibulum in, nibh. Vivamus volutpat eros ac eros posuere tristique. Nam posuere erat vitae eros. Suspendisse potenti. Integer mattis dolor ac purus. Donec est turpis, lacinia non, vulputate non, pellentesque eu, sem. Morbi mollis volutpat lacus. Donec vitae justo. Aliquam mattis lacus in ipsum cursus sollicitudin. Sed bibendum rutrum odio. Donec nulla justo, pulvinar et, faucibus eget, tempus non, quam.<br /><br />
+
+Morbi malesuada augue ac libero pellentesque faucibus. Donec egestas turpis ac nunc. Integer semper. Nam auctor justo ac enim. Curabitur diam elit, tristique ac, viverra eget, placerat ac, nisl. Aenean faucibus auctor diam. Nam sed augue. Duis posuere massa vel nulla. Integer diam sem, fermentum quis, dignissim eget, egestas quis, ante. Donec sit amet mauris. Mauris id mauris quis purus sagittis malesuada. Suspendisse in justo at ipsum pharetra pellentesque. In quis eros. Phasellus cursus, libero eu vulputate molestie, felis eros tempor dui, vel viverra nulla pede in dui. Nulla tortor massa, eleifend sed, dapibus et, mollis sollicitudin, diam. Integer vitae ipsum ac velit egestas dictum. Fusce sed neque ac erat sagittis elementum. Nulla convallis, sem id ullamcorper rhoncus, pede lorem imperdiet pede, eu pharetra nisi tortor ac felis.<br /><br />
+
+Donec fringilla. Mauris elit felis, tempor aliquam, fringilla quis, tempor et, ipsum. Mauris vestibulum, ante commodo tempus gravida, lectus sem volutpat magna, et blandit ante urna eget justo. Curabitur fermentum, ligula at interdum commodo, nibh nunc pharetra ante, eu dictum justo ligula sed tortor. Donec interdum eleifend sapien. Pellentesque pellentesque erat eu nunc. Vivamus vitae ligula sit amet mauris porta luctus. Nullam tortor. Aenean eget augue. Donec ipsum metus, pulvinar eget, consectetuer ac, luctus id, risus. Aliquam interdum eros molestie sapien. Vivamus et enim. Donec adipiscing cursus ante.<br /><br />
+
+Phasellus turpis elit, suscipit non, pellentesque nec, imperdiet eget, ante. Sed mauris nulla, tempus ut, fringilla id, tempus vitae, magna. Pellentesque luctus justo nec augue. Aliquam pharetra mollis magna. Nunc dui augue, sollicitudin ut, cursus eget, vestibulum eget, sem. Donec ac dolor eget enim sodales cursus. Morbi interdum. Cras vel eros non elit faucibus aliquet. Donec quis lectus ut libero sagittis lacinia. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec ante. Nam odio. Mauris turpis. Ut dolor. Aenean suscipit tellus a turpis.<br /><br />
+
+Ut mollis dolor ut felis. Aliquam euismod odio in dui. Donec tincidunt. Etiam malesuada velit nec lacus. Etiam ullamcorper feugiat odio. Sed quis urna. Morbi vehicula erat at sapien. Suspendisse potenti. Ut auctor sem ac odio. Nulla nec nisi. Aliquam iaculis ipsum non elit. Cras feugiat egestas lacus. Aenean eget nulla ac nisl feugiat scelerisque. Aenean posuere iaculis tellus. Duis posuere suscipit magna. Duis sagittis, massa sit amet fringilla tempus, nulla mi lobortis leo, in blandit quam felis in quam.<br /><br />
+
+Donec orci. Pellentesque purus. Suspendisse diam erat, posuere quis, tempor vestibulum, cursus in, mi. In vehicula urna ut lacus. Etiam sollicitudin purus vitae metus. In eget nisi ac enim mattis dictum. Duis quis nunc. Fusce ac neque eu sem aliquam porttitor. Integer at nisl vitae odio dictum gravida. Quisque laoreet, neque ac ultrices accumsan, arcu nibh dignissim justo, eu eleifend nibh pede non purus. Duis molestie eros eget risus. Curabitur nibh. Nunc at ipsum ultricies urna posuere sollicitudin. Nullam placerat. Aliquam varius ipsum sed nisl. Fusce condimentum, mauris a ornare venenatis, lorem risus vulputate leo, ac pellentesque ligula ligula vel lacus. Quisque at diam. Proin gravida mauris sed tellus. Curabitur enim.<br /><br />
+
+Vivamus luctus, erat a varius pellentesque, augue purus porttitor eros, non sollicitudin purus lorem et dui. Nunc magna. Nam in pede. Donec molestie justo eu ligula feugiat vulputate. Nunc euismod. Donec accumsan, velit vitae aliquet suscipit, massa augue mattis magna, a interdum nisi eros sit amet lacus. Suspendisse euismod enim sed leo. Donec nunc. Suspendisse tristique arcu ac elit. Suspendisse blandit dui. Suspendisse potenti. Integer mollis, nisi vitae lobortis dignissim, mauris arcu sagittis est, quis sodales turpis est a lacus. Morbi lacinia eros a velit. Aenean blandit, ligula ut facilisis facilisis, neque lectus interdum magna, vel dictum tortor leo non nisl. Quisque enim. Donec ut turpis. Phasellus cursus. Aenean sem. Suspendisse potenti. Vestibulum neque.<br /><br />
+
+Cras pulvinar tempus justo. Nulla facilisi. Sed id lorem consequat quam suscipit tincidunt. Donec ac ante. Duis leo lacus, ultrices et, mattis et, fringilla sit amet, tellus. Donec tincidunt. Nam non ligula et leo pellentesque hendrerit. Integer auctor consequat est. Morbi id magna. Nam massa nunc, dignissim ut, tincidunt nec, aliquet ac, purus. Etiam accumsan. Phasellus mattis sem in nibh. Morbi faucibus ligula eget lectus. Mauris libero felis, accumsan et, tincidunt quis, suscipit et, elit. Ut luctus, turpis ut iaculis tincidunt, lorem metus tempus sem, a lacinia quam metus nec justo. Integer molestie sapien vitae leo. Suspendisse tristique. Curabitur elit ante, vulputate ac, euismod in, vehicula tincidunt, metus. Quisque ac risus. Nunc est libero, pulvinar ac, sodales at, scelerisque at, nibh.<br /><br />
+
+Praesent id lacus. Sed vitae metus. Mauris iaculis luctus tellus. Phasellus dictum nunc. In metus orci, pellentesque sit amet, dictum et, tincidunt aliquam, dolor. Nulla malesuada. Phasellus lacus. Suspendisse leo risus, tincidunt vitae, varius sed, scelerisque id, massa. Suspendisse id elit. In vel justo eu sem vulputate molestie. Maecenas rhoncus imperdiet augue. Sed est justo, mattis dictum, dapibus eu, rhoncus vel, velit. Aenean velit urna, congue quis, convallis ullamcorper, aliquam id, tortor. Morbi tempor.<br /><br />
+
+Nunc mollis pede vitae sem. Nulla facilisi. Etiam blandit, magna sed ornare laoreet, est leo mattis sem, id dignissim orci nunc at nisl. In vel leo. Aliquam porttitor mi ut libero. Nulla eu metus. Integer et mi vitae leo adipiscing molestie. Ut in lacus. Curabitur eu libero. Vivamus gravida pharetra lectus. Quisque rutrum ultrices lectus. Integer convallis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nisi dolor, rhoncus et, tristique id, lacinia id, massa.<br /><br />
+
+Aenean elit. Praesent eleifend, lacus sed iaculis aliquet, nisl quam accumsan dui, eget adipiscing tellus lacus sit amet mauris. Maecenas iaculis, ligula sed pulvinar interdum, orci leo dignissim ante, id tempor magna enim nec metus. Cras ac nisl eu nisl auctor ullamcorper. Etiam malesuada ante nec diam. Quisque sed sem nec est lacinia tempor. Sed felis. Proin nec eros vitae odio blandit gravida. Proin ornare. Nunc eros. Nam enim. Nam lacinia. Quisque et odio sit amet turpis ultricies volutpat. Aenean varius. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras et mi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec consequat imperdiet lacus. Morbi lobortis pellentesque sem.<br /><br />
+
+Mauris id augue sed erat blandit rhoncus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lectus velit, varius at, eleifend id, gravida nec, elit. Nulla facilisi. Vestibulum tempus turpis eget nulla. Cras nisl mi, iaculis vel, dapibus id, facilisis vitae, dolor. Praesent turpis. Vestibulum scelerisque, neque sed rhoncus tincidunt, tellus sem consectetuer quam, vel accumsan nisl ipsum ac diam. Nulla tellus massa, dapibus id, consequat vehicula, elementum ac, lorem. Vestibulum faucibus faucibus nisl. Quisque mauris enim, rutrum vestibulum, venenatis vel, venenatis nec, sapien. Quisque vel sem a nibh rutrum tincidunt. Praesent metus velit, pretium vel, ornare non, elementum ut, purus. Quisque mauris magna, scelerisque sed, condimentum dictum, auctor vitae, nisi. Mauris sed ligula. Proin purus diam, sollicitudin vel, rutrum nec, imperdiet sit amet, erat.<br /><br />
+
+Aliquam a metus ac ipsum sagittis luctus. Quisque quis nisl in odio euismod pretium. Vestibulum quis mi. Maecenas imperdiet, mauris sit amet viverra aliquet, ligula augue imperdiet orci, a mollis dolor nisl nec arcu. Morbi metus magna, fringilla sed, mollis porttitor, condimentum ut, risus. Phasellus eu sapien eu felis auctor congue. Ut aliquam nisi ac dui. Morbi id leo eget nisi ultricies lobortis. Donec auctor. Praesent vulputate. Morbi viverra. Sed elementum arcu eu nibh. Fusce non velit nec dui lobortis posuere. Suspendisse pretium, tortor at cursus laoreet, elit lorem vulputate ipsum, at elementum nisi nisi non nunc. Vestibulum aliquam massa vitae neque. Praesent eget arcu sit amet lacus euismod interdum.<br /><br />
+
+Duis lectus massa, luctus a, vulputate ut, consequat ut, enim. Proin nisi augue, consectetuer nec, bibendum eget, tempor nec, nulla. Suspendisse eu lorem. Praesent posuere. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lorem. Integer vehicula. Curabitur lorem turpis, pulvinar a, commodo ut, scelerisque ac, tortor. Morbi id enim non est consectetuer aliquam. Etiam gravida metus porta orci. Vestibulum velit elit, bibendum non, consequat sit amet, faucibus non, lorem. Integer mattis, turpis nec hendrerit lacinia, pede urna tincidunt dui, vel lobortis lorem lorem ac magna.<br /><br />
+
+Curabitur faucibus. Nam a urna in diam egestas luctus. Curabitur mi neque, tincidunt vel, iaculis id, iaculis in, quam. Praesent sodales bibendum orci. Nulla eu nunc ut purus eleifend aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce vulputate lorem sit amet enim. Nulla feugiat pretium sapien. Curabitur eget eros. Aenean sagittis sagittis dui. Praesent vel eros vitae dolor varius malesuada. Mauris suscipit lacus at erat. Mauris vestibulum. In et enim nec eros ultricies ultricies. Maecenas tempus lorem.<br /><br />
+
+Morbi metus elit, posuere id, rutrum et, porttitor a, mauris. Aliquam in orci in augue sodales venenatis. Ut ac purus. Fusce pharetra libero eget ligula. Praesent vel mi vitae nulla mollis dictum. Sed metus lorem, malesuada in, dictum ut, tincidunt a, dolor. Mauris rutrum sem fringilla massa adipiscing vestibulum. Cras viverra aliquet ligula. Aliquam quis leo. Nullam volutpat egestas odio. Nullam suscipit velit. Ut dapibus, ipsum ut dictum viverra, dui purus pharetra lectus, nec imperdiet ante metus sed dolor. Donec suscipit velit eu elit. Vestibulum eget lacus id tellus pharetra suscipit. Phasellus pede. Nulla posuere, odio ac congue placerat, arcu erat faucibus nisi, fringilla facilisis ligula quam a orci. Morbi mollis urna. Maecenas felis. Sed at arcu.<br /><br />
+
+Nam sit amet orci vel libero sollicitudin facilisis. Nunc fermentum pretium est. Donec dictum massa ut nibh. In gravida ullamcorper mauris. Cras sed odio. Praesent dolor metus, mattis a, vestibulum ac, iaculis in, purus. Proin egestas cursus arcu. Nullam feugiat, diam pulvinar convallis aliquet, odio felis facilisis urna, eu commodo leo risus eget dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In sodales tellus eu lectus. Mauris pulvinar.<br /><br />
+
+Etiam sed mi vitae felis pellentesque mattis. Nunc at metus et est porttitor pellentesque. Mauris ligula velit, faucibus eu, aliquet a, sodales sed, libero. Nulla vulputate. Duis enim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi mattis mattis eros. Nullam id tellus ut arcu convallis dictum. Vestibulum tempus facilisis sem. Maecenas tempor.<br /><br />
+
+Pellentesque pellentesque vehicula lectus. Sed viverra adipiscing arcu. Proin auctor nisl id tellus. Nunc pulvinar viverra nibh. Aliquam posuere sapien non nunc. Maecenas tristique, tortor sed vulputate dictum, tortor elit consectetuer sapien, at malesuada nunc ligula mollis nisi. Curabitur nisi elit, scelerisque at, pharetra interdum, cursus sit amet, nisl. Mauris ornare, orci id convallis rutrum, purus justo laoreet ligula, at posuere sapien nisi quis dolor. Quisque viverra. Ut dapibus. Maecenas vulputate. Praesent bibendum metus vitae urna.<br /><br />
+
+Aliquam eget quam eleifend augue dictum pellentesque. Pellentesque diam neque, sodales vestibulum, imperdiet vitae, posuere at, ligula. In ac felis. Cras nisl. Pellentesque lobortis augue quis sapien. Maecenas suscipit tempor elit. Nulla pellentesque. Pellentesque lacus. Cras dignissim tortor et lectus. Donec cursus mauris eget nulla. Aenean facilisis facilisis pede. Nullam aliquet volutpat ante. Maecenas libero ante, fermentum id, hendrerit vehicula, ultrices ac, erat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi laoreet egestas felis. Nunc varius nulla id mauris. Maecenas id massa.<br /><br />
+
+Praesent pellentesque libero et mi. Ut semper nulla eu elit. Vivamus nibh eros, vestibulum eget, luctus a, faucibus et, ante. Duis elementum dolor sed turpis. Aliquam elit. Etiam accumsan volutpat mauris. Integer interdum porta diam. Sed sed erat. Curabitur tristique. Praesent non nunc. Praesent quam est, tempus a, ornare vitae, pellentesque quis, orci. Vivamus id nulla. Nam pede lacus, placerat ut, sollicitudin ut, sodales id, augue. Nullam ultricies. Sed ac magna. Mauris eu arcu sit amet velit rutrum rutrum. Sed eu felis vitae ipsum sollicitudin gravida. Proin in arcu. Maecenas rhoncus, quam at facilisis fermentum, metus magna tempus metus, quis egestas turpis sem non tortor.<br /><br />
+
+Ut euismod. Suspendisse tincidunt tincidunt nulla. In dui. Praesent commodo nibh. Pellentesque suscipit interdum elit. Ut vitae enim pharetra erat cursus condimentum. Sed tristique lacus viverra ante. Cras ornare metus sit amet nisi. Morbi sed ligula. Mauris sit amet nulla et libero cursus laoreet. Integer et dui. Proin aliquam, sapien vel tempor semper, lorem elit scelerisque nunc, at malesuada mi lorem vel tortor. Curabitur in sem. Pellentesque cursus. Curabitur imperdiet sapien. Aliquam vehicula consequat quam.<br /><br />
+
+Aliquam erat volutpat. Donec lacinia porttitor mauris. Suspendisse porttitor. Integer ante. Ut et risus vitae lacus consectetuer porttitor. Curabitur posuere aliquam nulla. Pellentesque eleifend, mauris eu commodo tincidunt, ligula pede bibendum libero, ut aliquet nisi tellus at justo. Suspendisse quis lectus. Quisque iaculis dapibus libero. Fusce aliquet mattis risus.<br /><br />
+
+Suspendisse rutrum purus a nibh. Etiam in urna. Pellentesque viverra rhoncus neque. Mauris eu nunc. Integer a risus et est suscipit condimentum. Nulla lectus mi, vulputate vitae, euismod at, facilisis a, quam. Quisque convallis mauris et ante. Nunc aliquet egestas lorem. Integer sodales ante et velit. Curabitur malesuada. Suspendisse potenti. Mauris accumsan odio in nulla. Vestibulum luctus eleifend lacus. Aenean diam. Nullam nec metus. Curabitur id eros a elit pulvinar mattis. Donec dignissim consequat sapien. Praesent dictum, metus eget malesuada pellentesque, risus ante ultrices neque, eu gravida augue mi a pede. Morbi ac justo.<br /><br />
+
+Donec tempus consequat mauris. Sed felis lorem, lobortis et, sodales sit amet, adipiscing a, eros. Vestibulum vitae nunc non lectus porta bibendum. Curabitur nulla. Proin auctor nisl eget lacus. Donec dignissim venenatis nibh. Suspendisse ullamcorper tempus augue. Donec dictum sodales ipsum. Phasellus ac urna sit amet purus sagittis ullamcorper. Etiam orci.<br /><br />
+
+Phasellus facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse eros purus, auctor ac, auctor sed, placerat tincidunt, mi. Aliquam nibh est, congue sed, tempus vitae, pellentesque in, dui. Nullam mattis dapibus urna. Morbi at lorem. Praesent lobortis, sem et interdum suscipit, erat justo mattis nisl, vitae pulvinar quam leo in turpis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam quis massa non sapien accumsan congue. Praesent adipiscing. Vivamus tempus aliquam nunc. Quisque id sem ac eros tincidunt mattis. Etiam magna augue, feugiat ut, pretium vitae, volutpat quis, turpis. Morbi leo. Ut tortor. Nunc non mi. Maecenas tincidunt massa eu ligula. Vestibulum at nibh.<br /><br />
+
+Nunc vestibulum. Curabitur at nunc ac nisl vulputate congue. Suspendisse scelerisque. Integer mi. In hac habitasse platea dictumst. Donec nulla. Sed sapien. Aenean ac purus. Duis elit erat, hendrerit at, adipiscing in, fermentum ut, nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;<br /><br />
+
+Donec elit. Duis consequat purus vitae mauris. Mauris a tortor vel mi fringilla hendrerit. Curabitur mi. Aliquam arcu nibh, bibendum quis, bibendum sed, ultricies sit amet, ante. Morbi tincidunt, justo pellentesque feugiat rhoncus, est enim luctus pede, id congue metus odio eu mi. Fusce blandit nunc a lorem. Cras non risus. Nullam magna eros, elementum eu, mollis viverra metus.
+ </body>
+</html>
diff --git a/dom/base/test/test_bug444546.html b/dom/base/test/test_bug444546.html
new file mode 100644
index 0000000000..4fec1754e0
--- /dev/null
+++ b/dom/base/test/test_bug444546.html
@@ -0,0 +1,160 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=444546
+-->
+<head>
+ <title>Test for Bug 444546</title>
+ <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ .up {
+ height: 14px;
+ width: 1px;
+ background: blue;
+ font-size: 11px;
+ color: white;
+ }
+ .down {
+ height: 14px;
+ width: 1px;
+ background: blue;
+ font-size: 11px;
+ color: white;
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=444546">Mozilla Bug 444546</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 444546 **/
+
+ var xhrCount = 5;
+ var xhrs = new Array();
+ var uploads = new Array();
+ var maxSize = 5000000;
+ var hugeString = new Array(maxSize + 1).join('a');
+
+ function updateProgress(evt) {
+ ++evt.target.pcounter;
+ var time = new Date().getTime();
+ // 350 - 200 = 150ms
+ if ((time - evt.target.prevTime) < 150) {
+ evt.target.log.parentNode.style.background = "red";
+ }
+ var diff = (time - evt.target.prevTime);
+ if (evt.target.min == -1 || evt.target.min > diff) {
+ evt.target.min = diff;
+ }
+ if (evt.target.max == -1 || evt.target.max < diff) {
+ evt.target.max = diff;
+ }
+
+ evt.target.log.textContent = diff + "ms";
+ evt.target.prevTime = time;
+ if (evt.lengthComputable) {
+ var fractionLoaded = (evt.loaded / evt.total);
+ if (fractionLoaded < 1) {
+ evt.target.log.style.width = (fractionLoaded * 400) + "px";
+ }
+ }
+ }
+
+ function loaded(evt) {
+ evt.target.log.style.width = "400px";
+ evt.target.log.style.background = "green";
+ if ("xhr" in evt.target) {
+ evt.target.xhr.prevTime = new Date().getTime();
+ evt.target.xhr.startTime = evt.target.xhr.prevTime;
+ }
+ var total = new Date().getTime() - evt.target.startTime;
+ evt.target.log.textContent = "total:" + total + "ms";
+ if (evt.target.pcounter) {
+ evt.target.log.textContent += " ," + evt.target.pcounter + "pe, avg:" +
+ parseInt((evt.target.prevTime - evt.target.startTime)/evt.target.pcounter) + "ms";
+ }
+ if (evt.target.min != -1) {
+ ok(evt.target.min >= 150, "Events fired too fast!");
+ evt.target.log.textContent += ", min:" + evt.target.min + "ms";
+ }
+ if (evt.target.max != -1) {
+ // Disabled for now.
+ //ok(evt.target.max <= 550, "Events didn't fire fast enough!");
+ evt.target.log.textContent += ", max:" + evt.target.max + "ms";
+ }
+ if ("upload" in evt.target) {
+ is(evt.total, maxSize * 10, "Wrong data!");
+ --xhrCount;
+ if (xhrCount == 0) {
+ // This is a hack. To get more progress events, server sends the data
+ // 10 times.
+ SimpleTest.finish();
+ } else {
+ setTimeout(start, 10);
+ }
+ } else {
+ is(evt.total, maxSize, "Wrong data!");
+ }
+ }
+
+ function start() {
+ var xhr = new XMLHttpRequest();
+ xhrs.push(xhr);
+ uploads.push(xhr.upload);
+ var container = document.createElement("tr");
+ var td1 = document.createElement("td");
+ container.appendChild(td1);
+ td1.textContent = xhrs.length + ".";
+ var td2 = document.createElement("td");
+ container.appendChild(td2);
+ var td3 = document.createElement("td");
+ container.appendChild(td3);
+ var uploadElement = document.createElement("div");
+ td2.appendChild(uploadElement);
+ uploadElement.className = "up";
+ var downloadElement = document.createElement("div");
+ td3.appendChild(downloadElement);
+ downloadElement.className = "down";
+ document.getElementById('tbody').appendChild(container);
+ xhr.log = downloadElement;
+ xhr.upload.log = uploadElement;
+ xhr.onprogress = updateProgress;
+ xhr.upload.onprogress = updateProgress;
+ xhr.onload = loaded;
+ xhr.upload.onload = loaded;
+ xhr.open("POST", "bug444546.sjs");
+ xhr.upload.prevTime = new Date().getTime();
+ xhr.upload.startTime = xhr.upload.prevTime;
+ xhr.upload.xhr = xhr;
+ xhr.pcounter = 0;
+ xhr.upload.pcounter = 0;
+ xhr.min = -1;
+ xhr.upload.min = -1;
+ xhr.max = -1;
+ xhr.upload.max = -1;
+ xhr.send(hugeString);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(function() { setTimeout(start, 10); });
+
+</script>
+</pre>
+ <table>
+ <tbody id="tbody">
+ <tr>
+ <td>XHR</td>
+ <td style="min-width: 410px;">upload</td>
+ <td style="min-width: 410px;">download</td>
+ </tr>
+ </tbody>
+ </table>
+</body>
+</html>
diff --git a/dom/base/test/test_bug444722.html b/dom/base/test/test_bug444722.html
new file mode 100644
index 0000000000..84a7873d18
--- /dev/null
+++ b/dom/base/test/test_bug444722.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=444722
+-->
+<head>
+ <title>Test for Bug 444722</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=444722">Mozilla Bug 444722</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 444722 **/
+var counter = 0;
+var testCount = 0;
+var xhrs = new Array();
+
+function loadHandler() {
+ ++counter;
+ ok(true, "load handler should have been called.");
+ if (counter == testCount) {
+ SimpleTest.finish();
+ }
+}
+
+function testXHR(method, hasData, data) {
+ ++testCount;
+ var xhr = new XMLHttpRequest();
+ xhr.open(method, "file_XHR_pass1.xml");
+ xhr.onload = loadHandler;
+ try {
+ if (hasData) {
+ xhr.send(data);
+ } else {
+ xhr.send();
+ }
+ } catch(ex) {
+ --testCount;
+ ok(false, "Calling XMLHttpRequest.send failed: " + ex);
+ }
+ // Keep XHR alive.
+ xhrs.push(xhr);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+testXHR("GET", false, null);
+testXHR("GET", true, null);
+testXHR("GET", true, "some data");
+
+testXHR("POST", false, null);
+testXHR("POST", true, null);
+testXHR("POST", true, "some data");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug448993.html b/dom/base/test/test_bug448993.html
new file mode 100644
index 0000000000..e7915c4431
--- /dev/null
+++ b/dom/base/test/test_bug448993.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=448993
+-->
+<head>
+ <title>Test for Bug 448993</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=448993">Mozilla Bug 448993</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 448993 **/
+
+function runTest() {
+ var a = document.getElementById("a");
+ var b = document.getElementById("b");
+ var c = document.getElementById("c")
+ var r = document.createRange();
+ r.setStart(b, 0);
+ r.setEnd(a, 2);
+ c.appendChild(b);
+ r.extractContents();
+ var s = document.createRange();
+ s.setEnd(b, 0);
+ SpecialPowers.gc();
+ s.deleteContents();
+ ok(true, "test did not crash");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+</script>
+</pre>
+<div id="a"><span id="b"></span><span id="c"></span></div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug450160.html b/dom/base/test/test_bug450160.html
new file mode 100644
index 0000000000..2b2f80e693
--- /dev/null
+++ b/dom/base/test/test_bug450160.html
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=450160
+-->
+<head>
+ <title>Test for Bug 450160</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=450160">Mozilla Bug 450160</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 450160 **/
+
+
+function testHTMLDocument() {
+ var doc = document.implementation.createHTMLDocument();
+ ok(!!doc.documentElement, "Document should have document element!");
+ ok(!!doc.body, "Should have .body!");
+ ok(doc instanceof HTMLDocument,
+ "Document should be an HTML document!");
+}
+
+function testSVGDocument() {
+ var docType1 =
+ document.implementation.createDocumentType("svg",
+ "-//W3C//DTD SVG 1.1//EN",
+ null);
+ ok(docType1, "No doctype?");
+ ok(docType1.ownerDocument, "docType should have ownerDocument!");
+ var doc1 = document.implementation.createDocument(null, null, docType1);
+ is(docType1.ownerDocument, doc1, "docType should have ownerDocument!");
+ ok(!doc1.documentElement, "Document shouldn't have document element!");
+ ok(!(doc1 instanceof HTMLDocument),
+ "Document shouldn't be an HTML document!");
+ ok(doc1 instanceof XMLDocument,
+ "Document should be an XML document!");
+
+ // SVG documents have .documentElement.
+ ok("documentElement" in doc1, "No .documentElement in document");
+
+ var docType2 =
+ document.implementation.createDocumentType("svg",
+ "-//W3C//DTD SVG 1.1//EN",
+ null);
+ var doc2 = document.implementation.createDocument("http://www.w3.org/2000/svg",
+ "svg", docType2);
+ ok(doc2.documentElement, "Document should have document element!");
+ is(doc2.documentElement.localName, "svg", "Wrong .documentElement!");
+}
+
+function testFooBarDocument() {
+ var docType1 =
+ document.implementation.createDocumentType("FooBar", "FooBar", null);
+ ok(docType1, "No doctype?");
+ ok(docType1.ownerDocument, "docType should have ownerDocument!");
+ var doc1 = document.implementation.createDocument(null, null, docType1);
+ is(docType1.ownerDocument, doc1, "docType should have ownerDocument!");
+ ok(!doc1.documentElement, "Document shouldn't have document element!");
+ ok(!(doc1 instanceof HTMLDocument),
+ "Document shouldn't be an HTML document!");
+
+ var docType2 =
+ document.implementation.createDocumentType("FooBar", "FooBar", null);
+ var doc2 = document.implementation.createDocument("FooBarNS",
+ "FooBar", docType2);
+ ok(doc2.documentElement, "Document should have document element!");
+ is(doc2.documentElement.namespaceURI, "FooBarNS", "Wrong namespaceURI!");
+ is(doc2.documentElement.localName, "FooBar", "Wrong localName!");
+}
+
+function testNullDocTypeDocument() {
+ var doc1 = document.implementation.createDocument(null, null, null);
+ ok(!doc1.documentElement, "Document shouldn't have document element!");
+ ok(!(doc1 instanceof HTMLDocument),
+ "Document shouldn't be an HTML document!");
+
+ var doc2 = document.implementation.createDocument("FooBarNS",
+ "FooBar", null);
+ ok(doc2.documentElement, "Document should have document element!");
+ is(doc2.documentElement.namespaceURI, "FooBarNS", "Wrong namespaceURI!");
+ is(doc2.documentElement.localName, "FooBar", "Wrong localName!");
+}
+
+testHTMLDocument();
+testSVGDocument();
+testFooBarDocument();
+testNullDocTypeDocument();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug451376.html b/dom/base/test/test_bug451376.html
new file mode 100644
index 0000000000..500f9bafee
--- /dev/null
+++ b/dom/base/test/test_bug451376.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=451376
+-->
+<head>
+ <title>Test for Bug 451376</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body onload="doTest()">
+ <a target="_blank"
+ title="IAccessibleText::attributes provides incorrect info after a mis-spelled word"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=451376">Mozilla Bug 451376</a>
+ <p id="display"></p>
+ <div id="content" style="display:none">
+ </div>
+ <pre id="test">
+
+ <div id="area"><button>btn1</button>text <button>btn2</button></div>
+
+ <script class="testbody" type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ function testRange(aRangeID,
+ aStartNode, aStartOffset,
+ aEndNode, aEndOffset,
+ aBeforeRangeNode, aBeforeRangeOffset,
+ aInRangeNode, aInRangeOffset,
+ aAfterRangeNode, aAfterRangeOffset)
+ {
+ var range = document.createRange();
+
+ range.setStart(aStartNode, aStartOffset);
+ range.setEnd(aEndNode, aEndOffset);
+
+ if (aBeforeRangeNode)
+ is(range.comparePoint(aBeforeRangeNode, aBeforeRangeOffset), -1,
+ "Wrong result for the point before the range '" + aRangeID + "'");
+ if (aInRangeNode)
+ is(range.comparePoint(aInRangeNode, aInRangeOffset), 0,
+ "Wrong result for the point inside the range '" + aRangeID + "'");
+ if (aAfterRangeNode)
+ is(range.comparePoint(aAfterRangeNode, aAfterRangeOffset), 1,
+ "Wrong result for the point after the range '" + aRangeID + "'");
+ // Comparare also start and end point
+ is(range.comparePoint(aStartNode, aStartOffset), 0,
+ "Wrong result for the start point '" + aRangeID + "'");
+ is(range.comparePoint(aEndNode, aEndOffset), 0,
+ "Wrong result for the end point '" + aRangeID + "'");
+ ok(range.isPointInRange(aStartNode, aStartOffset),
+ "Wrong result for the start point '" + aRangeID + "'");
+ ok(range.isPointInRange(aEndNode, aEndOffset),
+ "Wrong result for the end point '" + aRangeID + "'");
+ }
+
+ function doTest()
+ {
+ var area = document.getElementById("area");
+ var btn1 = area.firstChild;
+ var text = btn1.nextSibling;
+ var btn2 = area.lastChild;
+
+ testRange("range1", area, 0, area, 1,
+ null, 0,
+ area, 0,
+ area, 2);
+
+ testRange("range2", text, 2, text, 4,
+ text, 0,
+ text, 3,
+ text, 5);
+
+ testRange("range3", text, 4, area, 2,
+ text, 0,
+ text, 4,
+ area, 3);
+
+ SimpleTest.finish();
+ }
+ </script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug453521.html b/dom/base/test/test_bug453521.html
new file mode 100644
index 0000000000..4a93d7af9c
--- /dev/null
+++ b/dom/base/test/test_bug453521.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=453521
+-->
+<head>
+ <title>Test for Bug 453521</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=453521">Mozilla Bug 453521</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 453521 **/
+
+
+var r = document.createRange();
+r.setStart(document.documentElement, 0);
+r.setEnd(document.documentElement, 0);
+ok(r.extractContents() != null,
+ "range.extractContents() shouldn't return null.");
+is(r.extractContents().nodeType, Node.DOCUMENT_FRAGMENT_NODE,
+ "range.extractContents() should return a document fragment.");
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug453736.html b/dom/base/test/test_bug453736.html
new file mode 100644
index 0000000000..8cb8ebd9b9
--- /dev/null
+++ b/dom/base/test/test_bug453736.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=453736
+-->
+<head>
+ <title>Test for Bug 453736</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=453736">Mozilla Bug 453736</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 453736 **/
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ const scriptCreationFuncs = [
+ function() { return document.createElement("script"); },
+ function() { return document.createElementNS("http://www.w3.org/2000/svg", "script"); }
+ ];
+
+ const scriptContainers = ["div", "iframe", "noframes", "noembed"];
+ for (var i = 0; i < scriptContainers.length; ++i) {
+ for (var func of scriptCreationFuncs) {
+ var cont = scriptContainers[i];
+ var node = document.createElement(cont);
+ document.body.appendChild(node);
+ var s = func();
+ s.setAttribute("type", "application/javascript");
+ s.appendChild(document.createTextNode('window["'+cont+'ScriptRan"] = true'));
+
+ window[cont+"ScriptRan"] = false;
+ node.appendChild(s);
+ is(window[cont+"ScriptRan"], true,
+ "Script created with " + func +" should run when inserting in <"+cont+">");
+
+ window[cont+"ScriptRan"] = false;
+ document.body.appendChild(s);
+ is(window[cont+"ScriptRan"], false,
+ "Script created with " + func + " shouldn't run when moving out of <"+cont+">");
+
+ window[cont+"ScriptRan"] = false;
+ document.body.appendChild(s.cloneNode(true));
+ is(window[cont+"ScriptRan"], false,
+ "Clone of script inside <" + cont + "> created with " + func + " shouldn't run");
+ }
+ }
+
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug454325.html b/dom/base/test/test_bug454325.html
new file mode 100644
index 0000000000..96426ec82b
--- /dev/null
+++ b/dom/base/test/test_bug454325.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=454325
+-->
+<head>
+ <title>Test for Bug 454325</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=454325">Mozilla Bug 454325</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 454325 **/
+
+function testDocument1() {
+ var doc = document.implementation.createDocument("", "", null);
+ var html = doc.createElement('html');
+ doc.appendChild(html);
+ var body = doc.createElement('body');
+ html.appendChild(body);
+ var h1 = doc.createElement('h1');
+ var t1 = doc.createTextNode('Hello ');
+ h1.appendChild(t1);
+ var em = doc.createElement('em');
+ var t2 = doc.createTextNode('Wonderful');
+ em.appendChild(t2);
+ h1.appendChild(em);
+ var t3 = doc.createTextNode(' Kitty');
+ h1.appendChild(t3);
+ body.appendChild(h1);
+ var p = doc.createElement('p');
+ var t4 = doc.createTextNode(' How are you?');
+ p.appendChild(t4);
+ body.appendChild(p);
+ var r = doc.createRange();
+ r.selectNodeContents(doc);
+ is(r.toString(), "Hello Wonderful Kitty How are you?",
+ "toString() on range selecting Document gave wrong output");
+ r.setStart(h1, 3);
+ r.setEnd(p, 0);
+ // <html><body><h1>Hello <em>Wonder ful<\em> Kitty<\h1><p>How are you?<\p><\body></html>
+ // ^ -----^
+ is(r.toString(), "", "toString() on range crossing text nodes gave wrong output");
+ var c1 = r.cloneContents();
+ is(c1.childNodes.length, 2, "Wrong child nodes");
+ try {
+ is(c1.childNodes[0].localName, "h1", "Wrong child node");
+ is(c1.childNodes[1].localName, "p", "Wrong child node");
+ } catch(ex) {
+ ok(!ex, ex);
+ }
+
+ r.setStart(t2, 6);
+ r.setEnd(p, 0);
+ // <html><body><h1>Hello <em>Wonder ful<\em> Kitty<\h1><p>How are you?<\p><\body></html>
+ // ^----------------------^
+ is(r.toString(), "ful Kitty", "toString() on range crossing text nodes gave wrong output");
+ var c2 = r.cloneContents();
+ is(c2.childNodes.length, 2, "Wrong child nodes");
+ try {
+ is(c1.childNodes[0].localName, "h1", "Wrong child node");
+ is(c1.childNodes[1].localName, "p", "Wrong child node");
+ } catch(ex) {
+ ok(!ex, ex);
+ }
+
+ var e1 = r.extractContents();
+ is(e1.childNodes.length, 2, "Wrong child nodes");
+ try {
+ is(e1.childNodes[0].localName, "h1", "Wrong child node");
+ is(e1.childNodes[1].localName, "p", "Wrong child node");
+ } catch(ex) {
+ ok(!ex, ex);
+ }
+}
+
+function testDocument2() {
+ var doc = document.implementation.createDocument("", "", null);
+ var html = doc.createElement('html');
+ doc.appendChild(html);
+ var head = doc.createElement('head');
+ html.appendChild(head);
+ var foohead = doc.createElement('foohead');
+ html.appendChild(foohead);
+ var body = doc.createElement('body');
+ html.appendChild(body);
+ var d1 = doc.createElement('div');
+ head.appendChild(d1);
+ var t1 = doc.createTextNode("|||");
+ d1.appendChild(t1);
+ var d2 = doc.createElement("div");
+ body.appendChild(d2);
+ var d3 = doc.createElement("div");
+ d2.appendChild(d3);
+ var d4 = doc.createElement("div");
+ d2.appendChild(d4);
+ var r = doc.createRange();
+ r.setStart(t1, 1);
+ r.setEnd(d2, 2);
+ is(r.toString(), "||", "Wrong range");
+ var c1 = r.cloneContents();
+ var e1 = r.extractContents();
+ ok(c1.isEqualNode(e1), "Wrong cloning or extracting!");
+}
+
+function testSurroundContents() {
+ var div = document.createElement('div');
+ document.body.appendChild(div);
+ div.innerHTML = '<div>hello</div>world';
+ var innerDiv = div.firstChild;
+ var hello = innerDiv.firstChild;
+ var range = document.createRange();
+ range.setStart(hello, 0);
+ range.setEnd(hello, 5);
+ range.surroundContents(document.createElement('code'));
+ is(innerDiv.childNodes.length, 3, "Wrong childNodes count");
+ is(innerDiv.childNodes[0].nodeName, "#text", "Wrong node name (1)");
+ is(innerDiv.childNodes[0].textContent, "", "Wrong textContent (1)");
+ is(innerDiv.childNodes[1].nodeName, "CODE", "Wrong node name (2)");
+ is(innerDiv.childNodes[1].textContent, "hello", "Wrong textContent (2)");
+ is(innerDiv.childNodes[2].nodeName, "#text", "Wrong node name (3)");
+ is(innerDiv.childNodes[2].textContent, "", "Wrong textContent (3)");
+}
+
+function runTest() {
+ testDocument1();
+ testDocument2();
+ testSurroundContents();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug454326.html b/dom/base/test/test_bug454326.html
new file mode 100644
index 0000000000..d477db4288
--- /dev/null
+++ b/dom/base/test/test_bug454326.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=454326
+-->
+<head>
+ <title>Test for Bug 454326</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=454326">Mozilla Bug 454326</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<div id="partial-text-selection">Hello Hello <div></div>World!</div>
+<div id="partial-element-selection"><div id="begin">Hello Hello </div><div></div><div id="end">World!</div></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 454326 **/
+
+ function reinitPartialTextSelection() {
+ var pts = document.getElementById("partial-text-selection");
+ pts.textContent = null;
+ pts.appendChild(document.createTextNode("Hello Hello "));
+ pts.appendChild(document.createElement("div"));
+ pts.appendChild(document.createTextNode("World!"));
+ }
+
+
+ function doTest() {
+ var pts = document.getElementById("partial-text-selection");
+ var ex = null;
+ try {
+ var r1 = document.createRange();
+ r1.setStart(pts.firstChild, 6);
+ r1.setEnd(pts.lastChild, 6);
+ is(r1.toString(), "Hello World!", "Wrong range!");
+ r1.surroundContents(document.createElement("div"));
+ is(r1.toString(), "Hello World!", "Wrong range!");
+ } catch(e) {
+ ex = e;
+ }
+ is(ex, null, "Unexpected exception!");
+
+ reinitPartialTextSelection();
+ ex = null;
+ try {
+ var r2 = document.createRange();
+ r2.setStart(pts.firstChild, 6);
+ r2.setEnd(pts, 2);
+ is(r2.toString(), "Hello ", "Wrong range!");
+ r2.surroundContents(document.createElement("div"));
+ is(r2.toString(), "Hello ", "Wrong range!");
+ } catch(e) {
+ ex = e;
+ }
+ is(ex, null, "Unexpected exception!");
+
+ reinitPartialTextSelection();
+ ex = null;
+ try {
+ var r3 = document.createRange();
+ r3.setStart(pts, 1);
+ r3.setEnd(pts.lastChild, 6);
+ is(r3.toString(), "World!", "Wrong range!");
+ r3.surroundContents(document.createElement("div"));
+ is(r3.toString(), "World!", "Wrong range!");
+ } catch(e) {
+ ex = e;
+ }
+ is(ex, null, "Unexpected exception!");
+
+ reinitPartialTextSelection();
+ ex = null;
+ try {
+ var r3 = document.createRange();
+ r3.setStart(pts.firstChild, 6);
+ r3.setEnd(pts.firstChild.nextSibling, 0);
+ is(r3.toString(), "Hello ", "Wrong range!");
+ r3.surroundContents(document.createElement("div"));
+ is(r3.toString(), "Hello ", "Wrong range!");
+ } catch(e) {
+ ex = e;
+ is(e.name, "InvalidStateError", "Didn't get InvalidStateError exception!");
+ is(Object.getPrototypeOf(e), DOMException.prototype, "Didn't get DOMException!");
+ is(e.code, 11, "Didn't get INVALID_STATE_ERR exception!");
+ }
+ ok(ex, "There should have been an exception!");
+
+ reinitPartialTextSelection();
+ ex = null;
+ try {
+ var r3 = document.createRange();
+ r3.setStart(pts.firstChild.nextSibling, 0);
+ r3.setEnd(pts.lastChild, 6);
+ is(r3.toString(), "World!", "Wrong range!");
+ r3.surroundContents(document.createElement("div"));
+ is(r3.toString(), "World!", "Wrong range!");
+ } catch(e) {
+ ex = e;
+ is(e.name, "InvalidStateError", "Didn't get InvalidStateError exception!");
+ is(Object.getPrototypeOf(e), DOMException.prototype, "Didn't get DOMException!");
+ is(e.code, 11, "Didn't get INVALID_STATE_ERR exception!");
+ }
+ ok(ex, "There should have been an exception!");
+
+ ex = null;
+ try {
+ var pes = document.getElementById("partial-element-selection");
+ var r4 = document.createRange();
+ r4.setStart(pes.firstChild.firstChild, 6);
+ r4.setEnd(pes.lastChild.firstChild, 6);
+ is(r4.toString(), "Hello World!", "Wrong range!");
+ r4.surroundContents(document.createElement("div"));
+ is(r4.toString(), "Hello World!", "Wrong range!");
+ } catch(e) {
+ ex = e;
+ is(e.name, "InvalidStateError", "Didn't get InvalidStateError exception!");
+ is(Object.getPrototypeOf(e), DOMException.prototype, "Didn't get DOMException!");
+ is(e.code, 11, "Didn't get INVALID_STATE_ERR exception!");
+ }
+ ok(ex, "There should have been an exception!");
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ addLoadEvent(SimpleTest.finish);
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug455472.html b/dom/base/test/test_bug455472.html
new file mode 100644
index 0000000000..b99c8a3fae
--- /dev/null
+++ b/dom/base/test/test_bug455472.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=455472
+-->
+<head>
+ <title>Test for Bug 455472</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=455472">Mozilla Bug 455472</a>
+<p id="display"></p>
+<script>
+ var ran = [ false, false, false, false, false ];
+</script>
+<div id="content" style="display: none">
+ <iframe srcdoc="<script>parent.ran[0]=true</script>"></iframe>
+ <object id="o1" type="text/html" data="object_bug455472.html"></object>
+ <embed type="image/svg+xml" src="embed_bug455472.html">
+ <object type="text/html" data="data:application/octet-stream,<script>parent.ran[3]=true</script>"></object>
+ <embed type="image/svg+xml" src="data:application/octet-stream,<svg%20xmlns='http://www.w3.org/2000/svg'%20onload='parent.ran[4]=true'/>">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 455472 **/
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ var expected = [ true, true, true, false, false ];
+ is (expected.length, ran.length, "Length mismatch");
+ for (var i = 0; i < expected.length; ++i) {
+ is(ran[i], expected[i],
+ "Unexpected behavior in object " + i + " (0-based)");
+ }
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug455629.html b/dom/base/test/test_bug455629.html
new file mode 100644
index 0000000000..73d6a4c6f2
--- /dev/null
+++ b/dom/base/test/test_bug455629.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=455629
+-->
+<head>
+ <title>Test for Bug 455629</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=455629">Mozilla Bug 455629</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 455629 **/
+SimpleTest.waitForExplicitFinish();
+
+var done = 0;
+function doTest(name) {
+ var elem = $(name);
+ var doc = elem.getSVGDocument();
+ try {
+ doc.foopy = 42;
+ fail("Able to set cross origin property!");
+ } catch (e) {
+ ok(true, "unable to set non-allAccess property cross origin");
+ }
+
+ if (elem instanceof HTMLObjectElement) {
+ doc = elem.contentDocument;
+ try {
+ doc.foopy = 42;
+ fail("Able to set cross origin property!");
+ } catch (e) {
+ ok(true, "unable to set non-allAccess property cross origin");
+ }
+ }
+
+ if (++done == 2) {
+ SimpleTest.finish();
+ }
+}
+</script>
+
+<object id="obj"
+ type="image/svg+xml"
+ onload="doTest('obj')"
+ data="http://example.org/tests/dom/base/test/bug455629-helper.svg">
+</object>
+
+<embed id="emb"
+ type="image/svg+xml"
+ onload="doTest('emb')"
+ src="http://example.org/tests/dom/base/test/bug455629-helper.svg">
+</embed>
+
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug456262.html b/dom/base/test/test_bug456262.html
new file mode 100644
index 0000000000..253499aaa5
--- /dev/null
+++ b/dom/base/test/test_bug456262.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=456262
+-->
+<head>
+ <title>Test for Bug 456262</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=456262">Mozilla Bug 456262</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 456262 **/
+
+function runTest() {
+ document.expando = document;
+ document.documentElement.expando = document;
+ document.documentElement.setAttribute("foo", "bar");
+ document.documentElement.getAttributeNode("foo").expando = document;
+ SpecialPowers.gc();
+ ok(document.expando, "Should have preserved the expando!");
+ ok(document.documentElement.expando, "Should have preserved the expando!");
+ ok(document.documentElement.getAttributeNode('foo').expando,
+ "Should have preserved the expando!");
+}
+
+runTest();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug457746.html b/dom/base/test/test_bug457746.html
new file mode 100644
index 0000000000..807af1cac0
--- /dev/null
+++ b/dom/base/test/test_bug457746.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=457746
+-->
+<head>
+ <title>Test for Bug 457746</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=457746">Mozilla Bug 457746</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 457746 **/
+SimpleTest.waitForExplicitFinish();
+
+var xhr = new XMLHttpRequest();
+xhr.open("GET", "bug457746.sjs");
+xhr.send("");
+xhr.abort();
+xhr.open("GET", "bug457746.sjs");
+xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ is(xhr.responseText, "\u00c1", "Broken encoding conversion?");
+ SimpleTest.finish();
+ }
+}
+xhr.send("");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug459424.html b/dom/base/test/test_bug459424.html
new file mode 100644
index 0000000000..70acdc838c
--- /dev/null
+++ b/dom/base/test/test_bug459424.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=459424
+-->
+<head>
+ <title>Test for Bug 459424</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=459424">Mozilla Bug 459424</a>
+<p id="display" style="mask: url(no-such-document-I-tell-you#x)"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 459424 **/
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ SpecialPowers.setFullZoom(window, 2);
+ is(true, true, "Gotta test something");
+ SpecialPowers.setFullZoom(window, 1);
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug461555.html b/dom/base/test/test_bug461555.html
new file mode 100644
index 0000000000..c56baf229a
--- /dev/null
+++ b/dom/base/test/test_bug461555.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=461555
+-->
+<head>
+ <title>Test for Bug 461555</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=461555">Mozilla Bug 461555</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function writeIt(n) {
+ document.write("<span>" + n + "</span>");
+}
+
+function done() {
+ nodes = document.getElementsByTagName('span');
+ is(nodes.length, 3, "wrong length");
+ for (i = 0; i < nodes.length; ++i) {
+ is(nodes[i].textContent, String(i + 1), "wrong order");
+ }
+ SimpleTest.finish();
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+ done();
+});
+
+writeIt(1);
+
+</script>
+<script defer>
+writeIt(2);
+</script>
+<script>
+writeIt(3);
+</script>
diff --git a/dom/base/test/test_bug461735.html b/dom/base/test/test_bug461735.html
new file mode 100644
index 0000000000..e04c5cd72b
--- /dev/null
+++ b/dom/base/test/test_bug461735.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=461735
+-->
+<head>
+ <title>Test for Bug 461735</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=461735">Mozilla Bug 461735</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+var errorFired = false;
+window.onerror = function(message, uri, line) {
+ is(message, "Script error.", "Should have empty error message");
+ is(uri,
+ "http://mochi.test:8888/tests/dom/base/test/bug461735-redirect1.sjs",
+ "Should have pre-redirect error location URI");
+ is(line, 0, "Shouldn't have a line here");
+ errorFired = true;
+}
+</script>
+<script src="bug461735-redirect1.sjs"></script>
+<script>
+ is(errorFired, true, "Should have error in redirected different origin script");
+ errorFired = false;
+</script>
+<script type="application/javascript">
+window.onerror = function(message, uri, line) {
+ is(message, "ReferenceError: c is not defined", "Should have correct error message");
+ is(uri,
+ "http://mochi.test:8888/tests/dom/base/test/bug461735-redirect2.sjs",
+ "Unexpected error location URI");
+ is(line, 3, "Should have a line here");
+ errorFired = true;
+}
+</script>
+<script src="bug461735-redirect2.sjs"></script>
+<script>
+ is(errorFired, true, "Should have error in same origin script");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug465767.html b/dom/base/test/test_bug465767.html
new file mode 100644
index 0000000000..f9e08bcda9
--- /dev/null
+++ b/dom/base/test/test_bug465767.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=465767
+-->
+<head>
+ <title>Test for Bug 465767</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=465767">Mozilla Bug 465767</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 465767 **/
+
+function runTest() {
+ var node = document.createElement("div");
+ var e = null;
+ try {
+ document.implementation.createDocument("", "", null).adoptNode(node);
+ SpecialPowers.gc();
+ document.implementation.createDocument("", "", null).adoptNode(node);
+ } catch(ex) {
+ e = ex;
+ }
+ is(e, null, ".adoptNode didn't succeed!");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug466080.html b/dom/base/test/test_bug466080.html
new file mode 100644
index 0000000000..ef57e1c831
--- /dev/null
+++ b/dom/base/test/test_bug466080.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test bug 466080</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="frame1"
+ src="https://requireclientcert.example.com/tests/dom/base/test/bug466080.sjs">
+
+ This iframe should load the resource via the src-attribute from
+ a secure server which requires a client-cert. Doing this is
+ supposed to work, but further below in the test we try to load
+ the resource from the same url using a XHR, which should not work.
+
+ TODO : What if we change 'src' from JS? Would/should it load?
+
+</iframe>
+
+<script class="testbody" type="text/javascript">
+
+"use strict";
+
+onWindowLoad();
+
+let alltests = [
+
+// load resource from a relative url - this should work
+ { url:"bug466080.sjs",
+ status_check:"==200",
+ error:"XHR from relative URL"},
+
+// TODO - load the resource from a relative url via https..?
+
+// load a non-existing resource - should get "404 Not Found"
+ { url:"bug466080-does-not.exist",
+ status_check:"==404",
+ error:"XHR loading non-existing resource"},
+
+// load resource from cross-site non-secure server
+ { url:"http://test1.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"==200",
+ error:"XHR from cross-site plaintext server"},
+
+// load resource from cross-site secure server - should work since no credentials are needed
+ { url:"https://test1.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"==200",
+ error:"XHR from cross-site secure server"},
+
+// load resource from cross-site secure server - should work since the server just requests certs
+ { url:"https://requestclientcert.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"==200",
+ error:"XHR from cross-site secure server requesting certificate"},
+
+// load resource from cross-site secure server - should NOT work since the server requires cert
+// note that this is the url which is used in the iframe.src above
+ { url:"https://requireclientcert.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"!=200",
+ error:"XHR from cross-site secure server requiring certificate"},
+
+// repeat previous, - should NOT work
+ { url:"https://requireclientcert.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"==200",
+ error:"XHR w/ credentials from cross-site secure server requiring certificate",
+ withCredentials:"true"},
+
+// repeat previous, but with credentials - should work
+ { url:"https://requireclientcert.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"==200",
+ error:"XHR w/ credentials from cross-site secure server requiring certificate",
+ withCredentials:"true"},
+
+// repeat previous, withCredentials but using a weird method to force preflight
+// should NOT work since our preflight is anonymous and will fail with our simple server
+ { url:"https://requireclientcert.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"!=200",
+ error:"XHR PREFLIGHT from cross-site secure server requiring certificate",
+ withCredentials:"true",
+ method:"XMETHOD"},
+
+// repeat previous, withCredentials but using a weird method to force preflight
+// Set network.cors_preflight.allow_client_cert pref, that will allow cers on an
+// anonymous connection.
+// This should work since our preflight will work now.
+ { url:"https://requireclientcert.example.com/tests/dom/base/test/bug466080.sjs",
+ status_check:"==200",
+ error:"XHR PREFLIGHT from cross-site secure server requiring certificate",
+ withCredentials:"true",
+ method:"XMETHOD",
+ enableCertOnPreflight: true},
+
+ { cleanEnableCertOnPreflight: true},
+];
+
+async function onWindowLoad() {
+ // First, check that resource was loaded into the iframe
+ // This check in fact depends on bug #444165... :)
+ await new Promise(resolve => {
+ document.getElementById("frame1").onload = () => { resolve(); };
+ });
+
+ async function runTest(test) {
+ if (test.cleanEnableCertOnPreflight) {
+ await SpecialPowers.pushPrefEnv({"set": [["network.cors_preflight.allow_client_cert", false]]});
+ if (!alltests.length) {
+ SimpleTest.finish();
+ } else {
+ runTest(alltests.shift());
+ }
+ } else {
+ if (test.enableCertOnPreflight != null) {
+ await SpecialPowers.pushPrefEnv({"set": [["network.cors_preflight.allow_client_cert", true]]});
+ }
+ var xhr = new XMLHttpRequest();
+
+ var method = "GET";
+ if (test.method != null) { method = test.method; }
+ xhr.open(method, test.url);
+
+ xhr.withCredentials = test.withCredentials;
+
+ SpecialPowers.wrap(xhr).setRequestHeader("Connection", "Keep-Alive", false);
+
+ try {
+ xhr.send();
+ } catch(e) {
+ }
+
+ xhr.onloadend = function() {
+ var success = eval(xhr.status + test.status_check);
+ ok(success, test.error);
+
+ if (!alltests.length) {
+ SimpleTest.finish();
+ } else {
+ runTest(alltests.shift());
+ }
+ };
+ }
+ }
+
+ runTest(alltests.shift());
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug466409.html b/dom/base/test/test_bug466409.html
new file mode 100644
index 0000000000..b0255e24cf
--- /dev/null
+++ b/dom/base/test/test_bug466409.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=466409
+-->
+<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=466409">Mozilla Bug 466409</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="testframe"></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 466409 **/
+
+
+SimpleTest.waitForExplicitFinish();
+var testframe = document.getElementById('testframe');
+
+testframe.onload = function () {
+ ok(true, "page loaded successfully");
+ SimpleTest.finish();
+};
+testframe.src = "bug466409-page.html";
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug466751.xhtml b/dom/base/test/test_bug466751.xhtml
new file mode 100644
index 0000000000..b9756c0f9d
--- /dev/null
+++ b/dom/base/test/test_bug466751.xhtml
@@ -0,0 +1,40 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=466751
+-->
+<head>
+ <title>Test for Bug 466751</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=466751">Mozilla Bug 466751</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id="test" />
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript"><![CDATA[
+
+/** Test for Bug 466751 **/
+
+var el = $("test");
+var name, message;
+
+try {
+ el.innerHTML = '<div ">bla</div>';
+} catch (ex) {
+ name = ex.name;
+ message = ex.message;
+}
+
+const NS_ERROR_DOM_SYNTAX_ERR = 0x8053000C;
+ok(/An invalid or illegal string was specified/.test(message), "threw SyntaxError message");
+is(name, "SyntaxError", "threw SyntaxError");
+
+]]>
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug469020.html b/dom/base/test/test_bug469020.html
new file mode 100644
index 0000000000..f7f7631c93
--- /dev/null
+++ b/dom/base/test/test_bug469020.html
@@ -0,0 +1,128 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=469020
+-->
+<head>
+ <title>Test for Bug 469020</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=469020">Mozilla Bug 469020</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 469020 **/
+
+ var range = null;
+ var anchor = null;
+
+ function doRangeAnchor(elem, start, end) {
+ range = document.createRange();
+ range.setStart(elem.firstChild, start);
+ end = end < elem.lastChild.length ? end : elem.lastChild.length
+ range.setEnd(elem.lastChild, end);
+ anchor = document.createElement('a');
+ anchor.href = "javascript: void(0);";
+ range.surroundContents(anchor);
+ }
+
+ function undoRangeAnchor() {
+ var pnode = anchor.parentNode;
+ var range2 = document.createRange();
+ range2.selectNodeContents(anchor);
+ var contents = range2.extractContents();
+ pnode.replaceChild(contents,anchor);
+ }
+
+function serializeNode(node) {
+ var s;
+ var isElem = false;
+ if (node.nodeName == "#text") {
+ if (node.nodeValue) {
+ s = node.nodeValue
+ } else {
+ s = "<#empty>"
+ }
+ } else {
+ isElem = true;
+ s = "<" + node.nodeName + ">";
+ }
+ for (var j = 0; j < node.childNodes.length; ++j) {
+ s += serializeNode(node.childNodes[j]);
+ }
+ if (isElem) {
+ s += "</" + node.nodeName + ">";
+ }
+ return s;
+}
+
+function runTest(elementID, start, end, expected1, expected2, expected3) {
+ var e = document.getElementById(elementID);
+ doRangeAnchor(e, start, end);
+ is(serializeNode(e), expected1, "Wrong range behavior!");
+ document.getElementById('log').textContent += serializeNode(e) + "\n";
+ undoRangeAnchor();
+ is(serializeNode(e), expected2, "Wrong range behavior!");
+ document.getElementById('log').textContent += serializeNode(e) + "\n";
+ doRangeAnchor(e, start, end);
+ is(serializeNode(e), expected3, "Wrong range behavior!");
+ document.getElementById('log').textContent += serializeNode(e) + "\n";
+}
+
+function runTests() {
+ runTest("test1", 0, 3,
+ "<P><#empty><A>http://www.<SPAN>mozilla.</SPAN>org</A><#empty></P>",
+ "<P><#empty>http://www.<SPAN>mozilla.</SPAN>org<#empty></P>",
+ "<P><#empty><A><#empty>http://www.<SPAN>mozilla.</SPAN>org<#empty></A><#empty></P>");
+
+ runTest("test2", 1, 3,
+ "<P>h<A>ttp://www.<SPAN>mozilla.</SPAN>org</A><#empty></P>",
+ "<P>http://www.<SPAN>mozilla.</SPAN>org<#empty></P>",
+ "<P>h<A><#empty>ttp://www.<SPAN>mozilla.</SPAN>org<#empty></A><#empty></P>");
+
+ runTest("test3", 0, 2,
+ "<P><#empty><A>http://www.<SPAN>mozilla.</SPAN>or</A>g</P>",
+ "<P><#empty>http://www.<SPAN>mozilla.</SPAN>org</P>",
+ "<P><#empty><A><#empty>http://www.<SPAN>mozilla.</SPAN>org</A><#empty></P>");
+
+ runTest("test4", 1, 2,
+ "<P>h<A>ttp://www.<SPAN>mozilla.</SPAN>or</A>g</P>",
+ "<P>http://www.<SPAN>mozilla.</SPAN>org</P>",
+ "<P>h<A><#empty>ttp://www.<SPAN>mozilla.</SPAN>org</A><#empty></P>");
+
+ runTest("test5", 11, 0,
+ "<P>http://www.<A><#empty><SPAN>mozilla.</SPAN><#empty></A>org</P>",
+ "<P>http://www.<#empty><SPAN>mozilla.</SPAN><#empty>org</P>",
+ "<P>http://www.<A><#empty><#empty><SPAN>mozilla.</SPAN><#empty><#empty></A>org</P>");
+
+ runTest("test6", 10, 1,
+ "<P>http://www<A>.<SPAN>mozilla.</SPAN>o</A>rg</P>",
+ "<P>http://www.<SPAN>mozilla.</SPAN>org</P>",
+ "<P>http://www<A><#empty>.<SPAN>mozilla.</SPAN>or</A>g</P>");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTests);
+
+
+
+</script>
+</pre>
+<p id="test1">http://www.<span>mozilla.</span>org</p>
+<p id="test2">http://www.<span>mozilla.</span>org</p>
+<p id="test3">http://www.<span>mozilla.</span>org</p>
+<p id="test4">http://www.<span>mozilla.</span>org</p>
+<p id="test5">http://www.<span>mozilla.</span>org</p>
+<p id="test6">http://www.<span>mozilla.</span>org</p>
+<pre id="log">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug469304.html b/dom/base/test/test_bug469304.html
new file mode 100644
index 0000000000..c2c6532dd7
--- /dev/null
+++ b/dom/base/test/test_bug469304.html
@@ -0,0 +1,187 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=469304
+-->
+<head>
+ <title>Test for Bug 469304</title>
+ <script type="application/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=469304">Mozilla Bug 469304</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 469304 **/
+function testGetAttribute() {
+ var a1 = document.createAttributeNS("", "aa");
+ a1.nodeValue = "lowercase";
+ var a2 = document.createAttributeNS("", "AA");
+ a2.nodeValue = "UPPERCASE";
+ document.body.setAttributeNode(a1);
+ document.body.setAttributeNode(a2);
+ var log = document.getElementById("log");
+ is(document.body.getAttribute('aa'), "lowercase", "First attribute should have localname aa (1).");
+ is(document.body.getAttribute('AA'), "lowercase", "First attribute should have localname aa (2).");
+ is(document.body.getAttributeNS("", "aa"), "lowercase", "First attribute should have localName aa (3).");
+ is(document.body.getAttributeNS("", "AA"), "UPPERCASE", "Second attribute should have value UPPERCASE!");
+
+ var s = "";
+ for (var i = 0; i < document.body.attributes.length; ++i) {
+ s += document.body.attributes[i].nodeName + "=" +
+ document.body.attributes[i].nodeValue;
+ }
+ is(s, "aa=lowercaseAA=UPPERCASE", "Wrong attribute!");
+
+ is(document.body.getAttributeNode("aa"), document.body.getAttributeNode("AA"),
+ "Wrong node!");
+
+ document.body.getAttributeNodeNS("", "AA").nodeValue = "FOO";
+ is(document.body.getAttributeNS("", "AA"), "FOO", "Wrong value!");
+
+ document.body.removeAttributeNode(document.body.getAttributeNodeNS("", "aa"));
+ ok(!document.body.getAttributeNode("AA"), "Should not have attribute node! (1)");
+ ok(!document.body.getAttributeNode("aa"), "Should not have attribute node! (2)");
+
+ is(a2.nodeValue, "FOO", "Wrong value!");
+ a2.nodeValue = "UPPERCASE";
+ is(a2.nodeValue, "UPPERCASE", "Wrong value!");
+
+ document.body.setAttributeNode(a2);
+ is(document.body.getAttributeNS("", "AA"), "UPPERCASE", "Wrong value!");
+ ok(document.body.getAttributeNodeNS("", "AA"), "Should have attribute node!");
+ is(document.body.getAttributeNS("", "aa"), null, "No attribute has the localName aa.");
+ ok(!document.body.getAttributeNodeNS("", "aa"), "Should not have attribute node!");
+}
+testGetAttribute();
+
+// A bit modified testcases from WebKit.
+function testGetAttributeCaseInsensitive() {
+ var div = document.createElement('div');
+ div.setAttribute("mixedCaseAttrib", "x");
+ // Do original case lookup, and lowercase lookup.
+ return div.getAttribute("mixedcaseattrib");
+}
+is(testGetAttributeCaseInsensitive(), "x", "(1)");
+
+function testGetAttributeNodeMixedCase() {
+ var div = document.createElement('div');
+ var a = div.ownerDocument.createAttributeNS("", "mixedCaseAttrib");
+ a.nodeValue = "x";
+ div.setAttributeNode(a);
+ return div.getAttributeNS("", "mixedCaseAttrib");
+}
+is(testGetAttributeNodeMixedCase(), "x", "(2)");
+
+function testGetAttributeNodeLowerCase(div) {
+ var div = document.createElement('div');
+ var a = div.ownerDocument.createAttribute("lowercaseattrib");
+ a.nodeValue = "x";
+ div.setAttributeNode(a);
+ return div.getAttribute("lowerCaseAttrib");
+}
+is(testGetAttributeNodeLowerCase(), "x", "(3)");
+
+function testSetAttributeNodeKeepsRef(div) {
+ var div = document.createElement('div');
+ var a = div.ownerDocument.createAttribute("attrib_name");
+ a.nodeValue = "0";
+ div.setAttributeNode(a);
+ // Mutate the attribute node.
+ a.nodeValue = "1";
+ return div.getAttribute("attrib_name");
+}
+is(testSetAttributeNodeKeepsRef(), "1", "(4)");
+
+function testAttribNodeNameFoldsCase() {
+ var div = document.createElement('div');
+ var a = div.ownerDocument.createAttribute("A");
+ a.nodeValue = "x";
+ div.setAttributeNode(a);
+ var result = [ a.name, a.nodeName ];
+ return result.join(",");
+}
+is(testAttribNodeNameFoldsCase(), "a,a", "(5)");
+
+function testAttribNodeNameFoldsCaseGetNode() {
+ var body = document.body;
+ var a = body.ownerDocument.createAttribute("A");
+ a.nodeValue = "x";
+ body.setAttributeNode(a);
+ a = document.body.getAttributeNodeNS("", "a");
+ if (!a)
+ return "FAIL";
+ var result = [ a.name, a.nodeName ];
+ return result.join(",");
+}
+is(testAttribNodeNameFoldsCaseGetNode(), "a,a", "(6)");
+
+function testAttribNodeNameFoldsCaseGetNode2() {
+ var body = document.body;
+ var a = body.ownerDocument.createAttribute("B");
+ a.nodeValue = "x";
+ body.setAttributeNode(a);
+ a = document.body.getAttributeNodeNS("", "b");
+ if (!a)
+ return "FAIL";
+ // Now create node second time
+ a = body.ownerDocument.createAttribute("B");
+ a.nodeValue = "x";
+ body.setAttributeNode(a);
+ a = document.body.getAttributeNodeNS("", "b");
+ var result = [ a.name, a.nodeName ];
+ return result.join(",");
+}
+is(testAttribNodeNameFoldsCaseGetNode2(), "b,b", "(7)");
+
+function testAttribNodeNameGetMutate() {
+ var body = document.body;
+ var a = body.ownerDocument.createAttribute("c");
+ a.nodeValue = "0";
+ body.setAttributeNode(a);
+ a = document.body.getAttributeNode("c");
+ a.value = "1";
+ a = document.body.getAttributeNode("c");
+ return a.nodeValue;
+}
+is(testAttribNodeNameGetMutate(), "1", "(8)");
+
+var node = document.createElement("div");
+var attrib = document.createAttribute("myAttrib");
+attrib.nodeValue = "XXX";
+node.setAttributeNode(attrib);
+// Note, this is different to what WebKit does
+is((new XMLSerializer).serializeToString(node),
+ "<div xmlns=\"http://www.w3.org/1999/xhtml\" myattrib=\"XXX\"></div>", "(9)");
+is(node.getAttributeNode('myAttrib').name, "myattrib", "(10)");
+is(node.getAttributeNode('myattrib').name, "myattrib", "(11)");
+is(attrib.name, "myattrib", "(12)");
+
+var o = document.createElement("div");
+o.setAttribute("myAttrib","htmlattr");
+o.setAttributeNS("","myAttrib","123");
+is(o.getAttributeNodeNS("","myAttrib").nodeName, "myAttrib", "nodeName should be case-sensitive.");
+is(o.getAttributeNode("myAttrib").nodeName, "myattrib", "nodeName shouldn't be case-sensitive.");
+is(o.getAttributeNodeNS("","myAttrib").value, "123", "Should have got the case-sensitive attribute.");
+is(o.attributes.length, 2, "Should have two attributes.");
+o.setAttribute("myAttrib2", "htmlattr");
+o.setAttributeNS("", "myAttrib2", "123");
+is(o.attributes.length, 4, "Should have four attributes.");
+var an = o.attributes.removeNamedItem("myAttrib2");
+is(o.attributes.length, 3, "An attribute should have been removed.");
+is(an.value, "htmlattr", "The removed attribute should have been the case-insensitive attribute.");
+is(o.getAttribute("myAttrib2"), null, "Element shouldn't have case-insensitive attribute anymore.");
+var an2 = o.attributes.removeNamedItemNS("", "myAttrib2");
+is(an2.localName, "myAttrib2", "The removed attribute should be case-sensitive.");
+is(o.attributes.length, 2, "Element should have two attributes.");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug473162-1.html b/dom/base/test/test_bug473162-1.html
new file mode 100644
index 0000000000..f9025158de
--- /dev/null
+++ b/dom/base/test/test_bug473162-1.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=473162
+-->
+<head>
+ <title>Test for Bug 473162</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=473162">Mozilla Bug 473162</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<span id="TEST" class="TEST"></span>
+<span id="test" class="test"></span>
+<span id="Test" class="Test"></span>
+<span id="tesT" class="tesT"></span>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 473162 **/
+var nodes = document.getElementsByClassName("test");
+is(nodes.length, 1, "Unexpected length");
+is(nodes[0], $("test"), "Unexpected first node");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug473162-2.html b/dom/base/test/test_bug473162-2.html
new file mode 100644
index 0000000000..976c830675
--- /dev/null
+++ b/dom/base/test/test_bug473162-2.html
@@ -0,0 +1,33 @@
+<!-- NOTE: THIS TEST MUST BE IN QUIRKS MODE -->
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=473162
+-->
+<head>
+ <title>Test for Bug 473162</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=473162">Mozilla Bug 473162</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<span id="TEST" class="TEST"></span>
+<span id="test" class="test"></span>
+<span id="Test" class="Test"></span>
+<span id="tesT" class="tesT"></span>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 473162 **/
+var nodes = document.getElementsByClassName("test");
+is(nodes.length, 4, "Unexpected length");
+is(nodes[0], $("TEST"), "Unexpected first node");
+is(nodes[1], $("test"), "Unexpected second node");
+is(nodes[2], $("Test"), "Unexpected third node");
+is(nodes[3], $("tesT"), "Unexpected fourth node");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug475156.html b/dom/base/test/test_bug475156.html
new file mode 100644
index 0000000000..49bdb2b287
--- /dev/null
+++ b/dom/base/test/test_bug475156.html
@@ -0,0 +1,301 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=475156
+-->
+<head>
+ <title>Test for Bug 475156</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="drive(tests.shift());">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var path = "http://mochi.test:8888/tests/dom/base/test/";
+
+function fromCache(xhr)
+{
+ var ch = SpecialPowers.wrap(xhr).channel.QueryInterface(SpecialPowers.Ci.nsICacheInfoChannel);
+ return ch.isFromCache();
+}
+
+var tests = [
+ // First just init the file with an ETag
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs?etag=a1");
+ },
+
+ loading(xhr)
+ {
+ },
+
+ done(xhr)
+ {
+ },
+ },
+
+ // Try to load the file the first time regularly, we have to get 200 OK
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), false, "Not coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We get a fresh version of the file");
+ is(xhr.getResponseHeader("Etag"), "a1", "We got correct ETag");
+ is(xhr.responseText, "a1", "We got the expected file body");
+ },
+ },
+
+ // Try to load the file the second time regularly, we have to get 304 Not Modified
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a1");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), true, "Coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We got cached version");
+ is(xhr.getResponseHeader("Etag"), "a1", "We got correct ETag");
+ is(xhr.responseText, "a1", "We got the expected file body");
+ },
+ },
+
+ // Try to load the file the third time regularly, we have to get 304 Not Modified
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a1");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), true, "Coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We got cached version");
+ is(xhr.getResponseHeader("Etag"), "a1", "We got correct ETag");
+ is(xhr.responseText, "a1", "We got the expected file body");
+ },
+ },
+
+ // Now modify the ETag
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs?etag=a2");
+ },
+
+ loading(xhr)
+ {
+ },
+
+ done(xhr)
+ {
+ },
+ },
+
+ // Try to load the file, we have to get 200 OK with the new content
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a2");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), false, "Not coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We get a fresh version of the file");
+ is(xhr.getResponseHeader("Etag"), "a2", "We got correct ETag");
+ is(xhr.responseText, "a2", "We got the expected file body");
+ },
+ },
+
+ // Try to load the file the second time regularly, we have to get 304 Not Modified
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a2");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), true, "Coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We got cached version");
+ is(xhr.getResponseHeader("Etag"), "a2", "We got correct ETag");
+ is(xhr.responseText, "a2", "We got the expected file body");
+ },
+ },
+
+ // Try to load the file the third time regularly, we have to get 304 Not Modified
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a2");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), true, "Coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We got cached version");
+ is(xhr.getResponseHeader("Etag"), "a2", "We got correct ETag");
+ is(xhr.responseText, "a2", "We got the expected file body");
+ },
+ },
+
+ // Now modify the ETag ones more
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs?etag=a3");
+ },
+
+ loading(xhr)
+ {
+ },
+
+ done(xhr)
+ {
+ },
+ },
+
+ // Try to load the file, we have to get 200 OK with the new content
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a3");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), false, "Not coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We get a fresh version of the file");
+ is(xhr.getResponseHeader("Etag"), "a3", "We got correct ETag");
+ is(xhr.responseText, "a3", "We got the expected file body");
+ },
+ },
+
+ // Try to load the file the second time regularly, we have to get 304 Not Modified
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a3");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), true, "Coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We got cached version");
+ is(xhr.getResponseHeader("Etag"), "a3", "We got correct ETag");
+ is(xhr.responseText, "a3", "We got the expected file body");
+ },
+ },
+
+ // Try to load the file the third time regularly, we have to get 304 Not Modified
+ {
+ init(xhr)
+ {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a3");
+ },
+
+ loading(xhr)
+ {
+ is(fromCache(xhr), true, "Coming from the cache");
+ },
+
+ done(xhr)
+ {
+ is(xhr.status, 200, "We got cached version");
+ is(xhr.getResponseHeader("Etag"), "a3", "We got correct ETag");
+ is(xhr.responseText, "a3", "We got the expected file body");
+ },
+ },
+
+ // Load one last time to reset the state variable in the .sjs file
+ {
+ init (xhr) {
+ xhr.open("GET", path + "bug475156.sjs");
+ xhr.setRequestHeader("If-Match", "a1");
+ },
+
+ loading (xhr) {
+ },
+
+ done (xhr) {
+ },
+ },
+]
+
+
+function drive(test)
+{
+ SpecialPowers.pushPrefEnv({set: [["network.http.rcwn.enabled", false]]}, _=>{
+ var xhr = new XMLHttpRequest();
+ test.init(xhr);
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 3) {
+ test.loading(this);
+ }
+ if (this.readyState == 4) {
+ test.done(this);
+ if (!tests.length)
+ SimpleTest.finish();
+ else
+ drive(tests.shift());
+ }
+ }
+ xhr.send();
+ });
+}
+
+</script>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug482935.html b/dom/base/test/test_bug482935.html
new file mode 100644
index 0000000000..444c3aada7
--- /dev/null
+++ b/dom/base/test/test_bug482935.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test bug 482935</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href=" /tests/SimpleTest/test.css" />
+</head>
+<body onload="onWindowLoad()">
+<script class="testbody" type="text/javascript">
+
+var url = "bug482935.sjs";
+
+function clearCache() {
+ if (SpecialPowers.isMainProcess()) {
+ SpecialPowers.Cc["@mozilla.org/netwerk/cache-storage-service;1"].
+ getService(SpecialPowers.Ci.nsICacheStorageService).
+ clear();
+ }
+}
+
+// Tests that the response is cached if the request is cancelled
+// after it has reached state 4
+function testCancelInPhase4() {
+
+ clearCache();
+
+ // First request - should be loaded from server
+ var xhr = new XMLHttpRequest();
+ xhr.addEventListener("readystatechange", function() {
+ if (xhr.readyState < xhr.DONE) return;
+ is(xhr.readyState, xhr.DONE, "wrong readyState");
+ xhr.abort();
+ SimpleTest.executeSoon(function() {
+ // This request was cancelled, so the responseText should be empty string
+ is(xhr.responseText, "", "Expected empty response to cancelled request");
+
+ // Second request - should be found in cache
+ var xhr2 = new XMLHttpRequest();
+
+ xhr2.addEventListener("load", function() {
+ is(xhr2.responseText, "0", "Received fresh value for second request");
+ SimpleTest.finish();
+ });
+
+ xhr2.open("GET", url);
+ xhr2.setRequestHeader("X-Request", "1", false);
+
+ try { xhr2.send(); }
+ catch(e) {
+ is(xhr2.status, "200", "Exception!");
+ }
+ });
+ });
+
+ xhr.open("GET", url, true);
+ xhr.setRequestHeader("X-Request", "0", false);
+ try { xhr.send(); }
+ catch(e) {
+ is("Nothing", "Exception", "Boom: " + e);
+ }
+}
+
+function onWindowLoad() {
+ // Disable rcwn to make cache behavior deterministic.
+ SpecialPowers.pushPrefEnv({set: [["network.http.rcwn.enabled", false]]},
+ testCancelInPhase4);
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug484396.html b/dom/base/test/test_bug484396.html
new file mode 100644
index 0000000000..24c34b3b1e
--- /dev/null
+++ b/dom/base/test/test_bug484396.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=484396
+-->
+<head>
+ <title>Test for Bug 484396</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=484396">Mozilla Bug 484396</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var msg = 'xhr.open() succeeds with empty url';
+var xhr = new XMLHttpRequest();
+
+try {
+ xhr.open('GET', '');
+ ok(true, msg);
+} catch (e) {
+ ok(false, msg);
+}
+
+xhr.onerror = function () {
+ ok(false, 'xhr.send() succeeds with empty url');
+}
+
+xhr.onreadystatechange = function () {
+ if (4 == xhr.readyState) {
+ is(xhr.status, 200, 'xhr.status is 200 OK');
+ ok(-1 < xhr.responseText.indexOf('Bug 484396'), 'xhr.responseText contains the calling page');
+
+ SimpleTest.finish();
+ }
+};
+
+xhr.send('');
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug493881.html b/dom/base/test/test_bug493881.html
new file mode 100644
index 0000000000..a1ae21daa5
--- /dev/null
+++ b/dom/base/test/test_bug493881.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=493881
+-->
+
+<head>
+ <title>Test for Bug 493881</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="test_bug493881.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style type="text/css">
+
+ </style>
+</head>
+
+<body id="body">
+
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=493881"
+ target="_blank" >Mozilla Bug 493881</a>
+
+<p id="display"></p>
+
+<a id="nonvisitedlink" href="http://www.example.com/">Non-visited link</a>
+<a id="visitedlink" href="">Visited link</a>
+<p id="plaintext">some text</p>
+
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug493881.js b/dom/base/test/test_bug493881.js
new file mode 100644
index 0000000000..faee306c68
--- /dev/null
+++ b/dom/base/test/test_bug493881.js
@@ -0,0 +1,100 @@
+/**
+ * Test for Bug 493881: Changes to legacy HTML color properties before the BODY is loaded
+ * should be ignored. Additionally, after BODY loads, setting any of these properties to undefined
+ * should cause them to be returned as the string "undefined".
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var legacyProps = [
+ "fgColor",
+ "bgColor",
+ "linkColor",
+ "vlinkColor",
+ "alinkColor",
+];
+var testColors = ["blue", "silver", "green", "orange", "red"];
+var rgbTestColors = [
+ "rgb(255, 0, 0)",
+ "rgb(192, 192, 192)",
+ "rgb(0, 128, 0)",
+ "rgb(255, 165, 0)",
+ "rgb(255, 0, 0)",
+];
+var idPropList = [
+ { id: "plaintext", prop: "color" },
+ { id: "body", prop: "background-color" },
+ { id: "nonvisitedlink", prop: "color" },
+ { id: "visitedlink", prop: "color" },
+];
+var initialValues = [];
+
+function setAndTestProperty(prop, color) {
+ var initial = document[prop];
+ document[prop] = color;
+ is(document[prop], initial, "document[" + prop + "] not ignored before body");
+ return initial;
+}
+
+/**
+ * Attempt to set legacy color properties before BODY exists, and verify that such
+ * attempts are ignored.
+ */
+for (let i = 0; i < legacyProps.length; i++) {
+ initialValues[i] = setAndTestProperty(legacyProps[i], testColors[i]);
+}
+
+/**
+ * After BODY loads, run some more tests.
+ */
+addLoadEvent(function () {
+ // Verify that the legacy color properties still have their original values.
+ for (let i = 0; i < legacyProps.length; i++) {
+ is(
+ document[legacyProps[i]],
+ initialValues[i],
+ "document[" + legacyProps[i] + "] altered after body load"
+ );
+ }
+
+ // Verify that legacy color properties applied before BODY are really ignored when rendering.
+ // Save current computed style colors for later use.
+ for (let i = 0; i < idPropList.length; i++) {
+ var style = window.getComputedStyle(
+ document.getElementById(idPropList[i].id)
+ );
+ var color = style.getPropertyValue(idPropList[i].prop);
+ idPropList[i].initialComputedColor = color;
+ isnot(color, rgbTestColors[i], "element rendered using before-body style");
+ }
+ // XXX: Can't get links to visually activate via script events, so can't verify
+ // that the alinkColor property was not applied.
+
+ // Verify that setting legacy color props to undefined after BODY loads will cause them
+ // to be read as the string "undefined".
+ for (let i = 0; i < legacyProps.length; i++) {
+ document[legacyProps[i]] = undefined;
+ is(
+ document[legacyProps[i]],
+ "undefined",
+ "Unexpected value of " + legacyProps[i] + " after setting to undefined"
+ );
+ }
+
+ // Verify that setting legacy color props to undefined led to result
+ // of parsing undefined as a color.
+ for (let i = 0; i < idPropList.length; i++) {
+ var style = window.getComputedStyle(
+ document.getElementById(idPropList[i].id)
+ );
+ var color = style.getPropertyValue(idPropList[i].prop);
+ is(
+ color,
+ "rgb(0, 239, 14)",
+ "element's style should get result of parsing undefined as a color"
+ );
+ }
+
+ // Mark the test as finished.
+ setTimeout(SimpleTest.finish, 0);
+});
diff --git a/dom/base/test/test_bug498240.html b/dom/base/test/test_bug498240.html
new file mode 100644
index 0000000000..4bb66659d1
--- /dev/null
+++ b/dom/base/test/test_bug498240.html
@@ -0,0 +1,254 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=498240
+-->
+<head>
+ <title>Test for Bug 498240</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<style>
+ .container { border: 1px solid blue; display:block; }
+ b { color:blue; }
+ i { color:magenta; }
+</style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=498240">Mozilla Bug 498240</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 498240 **/
+
+
+function create(s) {
+ var p = document.createElement('span');
+ p.innerHTML = s;
+ p.setAttribute("class","container");
+ document.body.appendChild(p);
+ return p;
+}
+function select(start, startOffset, end, endOffset) {
+ var sel = getSelection();
+ sel.removeAllRanges();
+ var range = document.createRange();
+ range.setStart(start, startOffset);
+ range.setEnd(end, endOffset);
+ sel.addRange(range);
+}
+
+function insertClone(node) {
+ var sel = getSelection();
+ var range = sel.getRangeAt(0);
+ range.insertNode(node.cloneNode(true));
+}
+function insertCloneAtEnd(node) {
+ var sel = getSelection();
+ var range = sel.getRangeAt(0);
+ range.endContainer.insertBefore(node.cloneNode(true),range.endContainer.childNodes[range.endOffset]);
+}
+
+function check(start, startOffset, end, endOffset, s) {
+ var sel = getSelection();
+ var range = sel.getRangeAt(0);
+ is(range.startContainer, start, "wrong start node for range: '"+range.toString()+"'");
+ is(range.startOffset, startOffset, "wrong start offset for range: '"+range.toString()+"'");
+ is(range.endContainer, end, "wrong end node for range: '"+range.toString()+"'");
+ is(range.endOffset, endOffset, "wrong end offset for range: '"+range.toString()+"'");
+}
+
+function testInsertNode(node) {
+ var p;
+
+ p = create('a<b>bc</b>');
+ select(p.childNodes[0],0,p.childNodes[1],0);
+ insertClone(node);
+ check(p.childNodes[0],0,p.childNodes[3],0);
+
+ p = create('d<b>ef</b>');
+ select(p.childNodes[0],0,p.childNodes[1],1);
+ insertClone(node);
+ check(p.childNodes[0],0,p.childNodes[3],1);
+
+ p = create('g<b>h</b>');
+ select(p.childNodes[0],0,p.childNodes[0],0);
+ insertClone(node);
+ check(p.childNodes[0],0,p,2);
+
+ p = create('i<b>j</b>');
+ select(p.childNodes[0],1,p.childNodes[0],1);
+ insertClone(node);
+ check(p.childNodes[0],1,p,2);
+
+ p = create('k<b>l</b>');
+ select(p.childNodes[0],0,p.childNodes[1].childNodes[0],0);
+ insertClone(node);
+ check(p.childNodes[0],0,p.childNodes[3].childNodes[0],0);
+
+ p = create('m<b>no</b>');
+ select(p.childNodes[0],1,p.childNodes[1].childNodes[0],0);
+ insertClone(node);
+ check(p.childNodes[0],1,p.childNodes[3].childNodes[0],0);
+
+ p = create('p<b>qr</b>');
+ select(p.childNodes[0],1,p.childNodes[1].childNodes[0],1);
+ insertClone(node);
+ check(p.childNodes[0],1,p.childNodes[3].childNodes[0],1);
+
+ p = create('s<b>tu</b>');
+ select(p.childNodes[0],1,p.childNodes[1],0);
+ insertClone(node);
+ check(p.childNodes[0],1,p.childNodes[3],0);
+
+ p = create('<i>A</i><b>BC</b>');
+ select(p.childNodes[0],0,p.childNodes[1],0);
+ insertClone(node);
+ check(p.childNodes[0],0,p.childNodes[1],0);
+
+ p = create('<i>D</i><b>EF</b>');
+ select(p.childNodes[0],1,p.childNodes[1],1);
+ insertClone(node);
+ check(p.childNodes[0],1,p.childNodes[1],1);
+
+ p = create('<i></i><b>GH</b>');
+ select(p.childNodes[0],0,p.childNodes[1],0);
+ insertClone(node);
+ check(p.childNodes[0],0,p.childNodes[1],0);
+
+ p = create('<i>I</i><b>J</b>');
+ select(p,0,p.childNodes[1],0);
+ insertClone(node);
+ check(p,0,p.childNodes[2],0);
+
+ p = create('<i>K</i><b>L</b>');
+ select(p,0,p,2);
+ insertClone(node);
+ check(p,0,p,3);
+
+ p = create('<i>M</i><b>N</b>');
+ select(p,1,p,2);
+ insertClone(node);
+ check(p,1,p,3);
+
+ p = create('<i>O</i><b>P</b>');
+ select(p,1,p,1);
+ insertClone(node);
+ check(p,1,p,2);
+
+ p = create('<i>Q</i><b>R</b>');
+ select(p,2,p,2);
+ insertClone(node);
+ check(p,2,p,3);
+
+ p = create('<i>S</i><b>T</b>');
+ select(p,1,p,1);
+ insertCloneAtEnd(node);
+ check(p,1,p,1);
+
+ p = create('<i>U</i><b>V</b>');
+ select(p,2,p,2);
+ insertCloneAtEnd(node);
+ check(p,2,p,2);
+
+ p = create('<i>X</i><b>Y</b>');
+ select(p,0,p,1);
+ insertCloneAtEnd(node);
+ check(p,0,p,1);
+
+ p = create('<i>X</i><b><s>Y</s></b>');
+ select(p,0,p.childNodes[1],1);
+ insertCloneAtEnd(node);
+ check(p,0,p.childNodes[1],1);
+
+ p = create('<i>Z</i><b></b>');
+ select(p,0,p.childNodes[1],0);
+ insertCloneAtEnd(node);
+ check(p,0,p.childNodes[1],0);
+
+ p = create('<i>ZA</i><b><s>ZB</s><u>ZC</u></b>');
+ select(p,0,p.childNodes[1],1);
+ insertCloneAtEnd(node);
+ check(p,0,p.childNodes[1],1);
+}
+function testInvalidNodeType(node) {
+ try {
+ testInsertNode(node);
+ ok(false,"Expected an InvalidNodeTypeError");
+ } catch(e) {
+ is(e.name, "InvalidNodeTypeError", "Wrong exception, expected InvalidNodeTypeError");
+ ok(e instanceof DOMException, "Wrong type of exception: " + e);
+ is(e.code, DOMException.INVALID_NODE_TYPE_ERR, "Wrong exception code, expected INVALID_NODE_TYPE_ERR");
+ }
+}
+
+function runTest() {
+ testInsertNode(document.createTextNode('123'));
+
+ var i = document.createElement('SPAN')
+ i.innerHTML='456'
+ testInsertNode(i);
+
+ i = document.createDocumentFragment();
+ i.appendChild(document.createTextNode('789'));
+ testInsertNode(i);
+
+ /// DOM2 Traversal and Range Specification 2.13 "insertNode":
+ /// RangeException INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, or Document node.
+ // BUG: testInvalidNodeType(document.createAttribute('a'));
+ todo(false, "Test insertion of Entity node into range");
+ // TODO: testInvalidNodeType(document.createEntity());
+ todo(false, "Test insertion of Notation node into range");
+ // TODO: testInvalidNodeType(document.createNotation());
+ // BUG: testInvalidNodeType(document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null));
+
+ // Intentionally fails because of bug 418755.
+ todo(false, "test that Range::insertNode() throws WrongDocumentError when it should");
+ i = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null).createElement('html');
+ try {
+ testInsertNode(i);
+ todo(false,"Expected a WrongDocumentError");
+ } catch(e) {
+ is(e.name, "WrongDocumentError", "Wrong exception, expected WrongDocumentError");
+ ok(e instanceof DOMException, "Wrong type of exception: " + e);
+ is(e.code, DOMException.WRONG_DOCUMENT_ERR, "Wrong exception code, expected WRONG_DOCUMENT_ERR");
+ }
+
+ // Inserting an ancestor of the start container should throw HierarchyRequestError
+ todo(false, "test that Range::insertNode() throws HierarchyRequestError when it should");
+ var p = create('<b>IJK</b>');
+ select(p.childNodes[0],0,p.childNodes[0],1);
+ var sel = getSelection();
+ var range = sel.getRangeAt(0);
+ try {
+ range.insertNode(p);
+ ok(false,"Expected a HierarchyRequestError");
+ } catch(e) {
+ is(e.name, "HierarchyRequestError", "Wrong exception, expected HierarchyRequestError");
+ ok(e instanceof DOMException, "Wrong type of exception: " + e);
+ is(e.code, DOMException.HIERARCHY_REQUEST_ERR, "Wrong exception code, expected HIERARCHY_REQUEST_ERR");
+ }
+
+ // TODO: we should also have a test for:
+ /// "HierarchyRequestError: Raised if the container of the start of the Range is of a type
+ /// that does not allow children of the type of newNode"
+
+ todo(false, "InvalidStateError test goes here...");
+
+ var sel = getSelection();
+ sel.removeAllRanges();
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug498433.html b/dom/base/test/test_bug498433.html
new file mode 100644
index 0000000000..31ff4a4823
--- /dev/null
+++ b/dom/base/test/test_bug498433.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for HTML serializer</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=498433">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="testframe" src="file_htmlserializer_ipv6.html">
+ </iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+
+function loadFileContent(aFile, aCharset) {
+ if (aCharset == undefined)
+ aCharset = 'UTF-8';
+
+ var baseUri = SpecialPowers.Cc['@mozilla.org/network/standard-url-mutator;1']
+ .createInstance(SpecialPowers.Ci.nsIURIMutator)
+ .setSpec(window.location.href)
+ .finalize();
+
+ var ios = SpecialPowers.Cc['@mozilla.org/network/io-service;1']
+ .getService(SpecialPowers.Ci.nsIIOService);
+ var chann = ios.newChannel(aFile,
+ aCharset,
+ baseUri,
+ null, // aLoadingNode
+ SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal(),
+ null, // aTriggeringPrincipal
+ SpecialPowers.Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ SpecialPowers.Ci.nsIContentPolicy.TYPE_OTHER);
+
+ var cis = SpecialPowers.Ci.nsIConverterInputStream;
+
+ var inputStream = SpecialPowers.Cc["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(cis);
+ inputStream.init(chann.open(), aCharset, 1024, cis.DEFAULT_REPLACEMENT_CHARACTER);
+ var str = {}, content = '';
+ while (inputStream.readString(4096, str) != 0) {
+ content += str.value;
+ }
+ return content;
+}
+
+function isRoughly(actual, expected, message) {
+ return is(actual.replace("<!DOCTYPE HTML", "<!DOCTYPE html"),
+ expected,
+ message);
+}
+
+function testHtmlSerializer_1 () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder;
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("text/html");
+
+ var doc = $("testframe").contentDocument;
+ var out, expected;
+
+ // in the following tests, we must use the OutputLFLineBreak flag, to avoid
+ // to have the default line break of the platform in the result, so the test
+ // can pass on all platform
+
+ //------------ no flags
+ encoder.init(doc, "text/html", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_ipv6_out.html");
+ isRoughly(out, expected, "test no flags");
+ //------------ OutputAbsoluteLinks
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputAbsoluteLinks);
+ encoder.setCharset("UTF-8");
+ out = encoder.encodeToString();
+ expected = loadFileContent("file_htmlserializer_ipv6_out.html");
+ isRoughly(out, expected, "test OutputAbsoluteLinks");
+ //------------ serializing a selection
+ encoder.init(doc, "text/html", de.OutputLFLineBreak | de.OutputAbsoluteLinks);
+ encoder.setNode(doc.links[0]);
+ out = encoder.encodeToString();
+ expected = "<a href=\"http://[2001:4860:a003::68]/\">Test</a>";
+ isRoughly(out, expected, "test selection");
+
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlSerializer_1);
+
+</script>
+</pre>
+
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug498897.html b/dom/base/test/test_bug498897.html
new file mode 100644
index 0000000000..848bf73698
--- /dev/null
+++ b/dom/base/test/test_bug498897.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=498897
+-->
+<head>
+ <title>Test for Bug 498897</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=498897">Mozilla Bug 498897</a>
+<p id="display"><iframe id="testframe"></iframe></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 498897 **/
+
+var checkedLoad = false;
+
+const Cc = SpecialPowers.Cc;
+const Ci = SpecialPowers.Ci;
+
+// Content policy / factory implementation for the test
+var policyID = SpecialPowers.wrap(SpecialPowers.Components).ID("{65944d64-2390-422e-bea3-80d0af7f69ef}");
+var policyName = "@mozilla.org/498897_testpolicy;1";
+var policy = {
+ // nsISupports implementation
+ QueryInterface(iid) {
+ if (iid.equals(Ci.nsISupports) ||
+ iid.equals(Ci.nsIFactory) ||
+ iid.equals(Ci.nsIContentPolicy))
+ return this;
+
+ throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
+ },
+
+ // nsIFactory implementation
+ createInstance(iid) {
+ return this.QueryInterface(iid);
+ },
+
+ // nsIContentPolicy implementation
+ shouldLoad(contentLocation, loadInfo, mimeTypeGuess) {
+ var url = window.location.href.substr(0, window.location.href.indexOf('test_bug498897'));
+ let loadingPrincipal = loadInfo.loadingPrincipal;
+ if (loadingPrincipal) {
+ requestOrigin = loadingPrincipal.spec;
+ }
+ if (contentLocation.spec == url + "file_bug498897.css" &&
+ requestOrigin == url + "file_bug498897.html") {
+ checkedLoad = true;
+ }
+
+ return Ci.nsIContentPolicy.ACCEPT;
+ },
+
+ shouldProcess(contentLocation, loadInfo, mimeTypeGuess) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+}
+policy = SpecialPowers.wrapCallbackObject(policy);
+
+var componentManager = SpecialPowers.wrap(SpecialPowers.Components).manager
+ .QueryInterface(Ci.nsIComponentRegistrar);
+componentManager.registerFactory(policyID, "Test content policy for bug 498897",
+ policyName, policy);
+
+var categoryManager =
+ Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
+categoryManager.addCategoryEntry("content-policy", policyName, policyName,
+ false, true);
+
+function testFinished()
+{
+ ok(checkedLoad, "Content policy didn't get called!");
+
+ categoryManager.deleteCategoryEntry("content-policy", policyName, false);
+
+ setTimeout(function() {
+ componentManager.unregisterFactory(policyID, policy);
+
+ SimpleTest.finish();
+ }, 0);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+document.getElementById("testframe").src = "file_bug498897.html";
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug499656.html b/dom/base/test/test_bug499656.html
new file mode 100644
index 0000000000..bfc273ecf4
--- /dev/null
+++ b/dom/base/test/test_bug499656.html
@@ -0,0 +1,57 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=499656
+-->
+<head>
+ <title>Test for Bug 499656</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=499656">Mozilla Bug 499655</a>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 499655 **/
+
+div1 = document.createElementNS("http://www.w3.org/1999/xhtml","test");
+div2 = document.createElementNS("http://www.w3.org/1999/xhtml","TEst");
+div3 = document.createElementNS("test","test");
+div4 = document.createElementNS("test","TEst");
+div5 = document.createElement("test");
+div6 = document.createElement("TEst");
+
+content = document.getElementById("content");
+
+content.appendChild(div1);
+content.appendChild(div2);
+content.appendChild(div3);
+content.appendChild(div4);
+content.appendChild(div5);
+content.appendChild(div6);
+
+list = document.getElementsByTagName('test');
+is(list.length, 4, "Number of elements found");
+ok(list[0] == div1, "First element didn't match");
+ok(list[1] == div3, "Third element didn't match");
+ok(list[2] == div5, "Fifth element didn't match");
+ok(list[3] == div6, "Sixth element didn't match");
+
+list = document.getElementsByTagName('TEst');
+is(list.length, 4, "Wrong number of elements found");
+ok(list[0] == div1, "First element didn't match");
+ok(list[1] == div4, "Fourth element didn't match");
+ok(list[2] == div5, "Fifth element didn't match");
+ok(list[3] == div6, "Sixth element didn't match");
+
+list = document.getElementsByTagNameNS('test', 'test');
+is(list.length, 1, "Wrong number of elements found");
+ok(list[0] == div3, "Third element didn't match");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug499656.xhtml b/dom/base/test/test_bug499656.xhtml
new file mode 100644
index 0000000000..926fe2b65d
--- /dev/null
+++ b/dom/base/test/test_bug499656.xhtml
@@ -0,0 +1,57 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=499655
+-->
+<head>
+ <title>Test for Bug 499655</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=499655">Mozilla Bug 499655</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+div1 = document.createElementNS("http://www.w3.org/1999/xhtml","test");
+div2 = document.createElementNS("http://www.w3.org/1999/xhtml","TEst");
+div3 = document.createElementNS("test","test");
+div4 = document.createElementNS("test","TEst");
+div5 = document.createElement("test");
+div6 = document.createElement("TEst");
+
+content = document.getElementById("content");
+
+content.appendChild(div1);
+content.appendChild(div2);
+content.appendChild(div3);
+content.appendChild(div4);
+content.appendChild(div5);
+content.appendChild(div6);
+
+
+list = document.getElementsByTagName('test');
+is(list.length, 3, "Number of elements found");
+ok(list[0] == div1, "First element didn't match");
+ok(list[1] == div3, "Third element didn't match");
+ok(list[2] == div5, "Fifth element didn't match");
+
+list = document.getElementsByTagName('TEst');
+is(list.length, 3, "Number of elements found");
+ok(list[0] == div2, "Second element didn't match");
+ok(list[1] == div4, "Fourth element didn't match");
+ok(list[2] == div6, "Sixth element didn't match");
+
+list = document.getElementsByTagNameNS('test', 'test');
+is(list.length, 1, "Wrong number of elements found");
+ok(list[0] == div3, "Third element didn't match");
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug500937.html b/dom/base/test/test_bug500937.html
new file mode 100644
index 0000000000..b3d254ae58
--- /dev/null
+++ b/dom/base/test/test_bug500937.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=500937
+-->
+<head>
+ <title>Test for Bug 500937</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=500937">Mozilla Bug 500937</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id=iframe src="about:blank"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 500937 **/
+
+var d = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", null);
+var h = d.documentElement;
+h.appendChild(d.createElementNS("http://www.w3.org/1999/xhtml", "head"));
+var b = d.createElementNS("http://www.w3.org/1999/xhtml", "body");
+h.appendChild(b);
+
+b.appendChild(d.createElementNS("http://www.w3.org/1999/xhtml", "div"));
+b.appendChild(d.createElementNS("http://www.w3.org/1999/xhtml", "script"));
+b.appendChild(d.createElementNS("http://www.w3.org/1999/xhtml", "br"));
+b.appendChild(d.createElementNS("http://www.w3.org/1999/xhtml", "source"));
+b.appendChild(d.createElementNS("http://www.w3.org/1999/xhtml", "param"));
+b.appendChild(d.createTextNode("\u00A0"));
+
+is(new XMLSerializer().serializeToString(d),
+ '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><div></div><script><\/script><br /><source /><param />\u00A0</body></html>',
+ "XML DOM input to XMLSerializer");
+
+d = document.getElementById('iframe').contentWindow.document;
+
+while(d.documentElement.previousSibling) {
+ d.removeChild(d.documentElement.previousSibling);
+}
+
+d.replaceChild(h, d.documentElement);
+
+is(new XMLSerializer().serializeToString(d),
+ '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><div></div><script><\/script><br /><source /><param />\u00A0</body></html>',
+ "HTML DOM input to XMLSerializer");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug503473.html b/dom/base/test/test_bug503473.html
new file mode 100644
index 0000000000..586fb20529
--- /dev/null
+++ b/dom/base/test/test_bug503473.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=503473
+-->
+<head>
+ <title>Test for Bug 503473</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=503473">Mozilla Bug 503473</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 503473 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function done() {
+ var iframe = document.getElementById("iframe");
+ var divs = iframe.contentWindow.document.getElementsByTagName("div").length;
+ is(divs, 0, "Div wasn't blown away.")
+
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+<div id="content" style="display: none">
+ <iframe id='iframe' src="file_bug503473-frame.sjs">
+ </iframe>
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug503481.html b/dom/base/test/test_bug503481.html
new file mode 100644
index 0000000000..98db4893e2
--- /dev/null
+++ b/dom/base/test/test_bug503481.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=503481
+-->
+<head>
+ <title>Test for Bug 503481</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="done();">
+
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=503481"
+ target="_blank" >Mozilla Bug 503481</a>
+
+<p id="display"></p>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+function done() {
+ is(firstRan, true, "first has run");
+ is(secondRan, true, "second has run");
+ is(thirdRan, true, "third has run");
+ SimpleTest.finish();
+}
+var reqs = [];
+function unblock(s) {
+ xhr = new XMLHttpRequest();
+ xhr.open("GET", "file_bug503481.sjs?unblock=" + s);
+ xhr.send();
+ reqs.push(xhr);
+}
+var firstRan = false, secondRan = false, thirdRan = false;
+function runFirst() { firstRan = true; }
+function runSecond() {
+ is(thirdRan, true, "should have run third already");
+ secondRan = true;
+}
+function runThird() {
+ is(secondRan, false, "shouldn't have unblocked second yet");
+ thirdRan = true;
+ unblock("B");
+}
+</script>
+<script id=firstScript async src="file_bug503481.sjs?blockOn=A&body=runFirst();"></script>
+<script id=firstScriptHelper>
+is(document.getElementById("firstScript").async, true,
+ "async set");
+is(document.getElementById("firstScriptHelper").async, false,
+ "async not set");
+document.getElementById("firstScript").async = false;
+is(document.getElementById("firstScript").async, false,
+ "async no longer set");
+is(document.getElementById("firstScript").hasAttribute("async"), false,
+ "async attribute no longer set");
+is(firstRan, false, "First async script shouldn't have run");
+unblock("A");
+</script>
+
+<script async src="file_bug503481.sjs?blockOn=B&body=runSecond();"></script>
+<script async src="file_bug503481.sjs?blockOn=C&body=runThird();"></script>
+<script>
+is(secondRan, false, "Second async script shouldn't have run");
+is(thirdRan, false, "Third async script shouldn't have run");
+unblock("C");
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug503481b.html b/dom/base/test/test_bug503481b.html
new file mode 100644
index 0000000000..e11fe36116
--- /dev/null
+++ b/dom/base/test/test_bug503481b.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=503481
+-->
+<head>
+ <title>Test for Bug 503481</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=503481"
+ target="_blank" >Mozilla Bug 503481</a>
+
+<iframe src="file_bug503481b_inner.html"></iframe>
+<script>
+SimpleTest.waitForExplicitFinish();
+// script in the iframe will call SimpleTest.finish()
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug51034.html b/dom/base/test/test_bug51034.html
new file mode 100644
index 0000000000..b81fb3cb65
--- /dev/null
+++ b/dom/base/test/test_bug51034.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=51034
+-->
+<head>
+ <title>Test for Bug 51034</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=51034">Mozilla Bug 51034</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id="divElement">
+ <span>Subelement1</span>
+ <span>Subelement2</span>
+ <span>Subelement3</span>
+ </div>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 51034 **/
+var x = document.getElementById('divElement');
+
+isOK = false;
+try {
+x.getElementsByTagName('span');
+isOK = true;
+} catch (ex) {
+ isOK = false;
+}
+
+ok(isOK, "getElementsByTagName() doesn't cause exception");
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug513194.html b/dom/base/test/test_bug513194.html
new file mode 100644
index 0000000000..d32a164561
--- /dev/null
+++ b/dom/base/test/test_bug513194.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=513194
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 513194</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=631615"
+ >Mozilla Bug 513194</a>
+<script>
+// The use of document.write is deliberate. We are testing for the
+// HTML parser to call the CSS parser once and only once when it
+// encounters a new <style> element.
+SpecialPowers.wrap(window).docShell.cssErrorReportingEnabled = true;
+SimpleTest.runTestExpectingConsoleMessages(
+ function () { document.write("<style>qux { foo : bar; }<\/style>") },
+ [{ errorMessage: /Unknown property/ }]
+);
+</script>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug5141.html b/dom/base/test/test_bug5141.html
new file mode 100644
index 0000000000..2abafdcd10
--- /dev/null
+++ b/dom/base/test/test_bug5141.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=5141
+-->
+<head>
+ <title>Test for Bug 5141</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=5141">Mozilla Bug 5141</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 5141 **/
+var baz = document.createElement('img');
+ok(baz.parentNode === null, "Node.parentNode should be null for standalone nodes");
+
+
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug514487.html b/dom/base/test/test_bug514487.html
new file mode 100644
index 0000000000..40c3ea7fd4
--- /dev/null
+++ b/dom/base/test/test_bug514487.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html id="root">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=514487
+-->
+<head id="child">
+ <title>Test for Bug 514487</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTests()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=514487">Mozilla Bug 514487</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 514487 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ function runTests() {
+ // Test XML document cloning.
+ var d = (new DOMParser()).parseFromString(
+ "<html xmlns='http://www.w3.org/1999/xhtml' id='root'><foo id='child'/></html>",
+ "text/xml");
+ var cloneDoc = d.cloneNode(true);
+ ok(cloneDoc.getElementById("root"),
+ "XML document should have an element with ID 'root'");
+ ok(cloneDoc.getElementById("child"),
+ "XML document should have an element with ID 'child'");
+
+ // Test HTML cloning.
+ cloneDoc = document.cloneNode(true);
+ ok(cloneDoc.getElementById("root"),
+ "HTML document should have an element with ID 'root'");
+ ok(cloneDoc.getElementById("child"),
+ "HTML document should have an element with ID 'child'");
+ SimpleTest.finish();
+ }
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug515401.html b/dom/base/test/test_bug515401.html
new file mode 100644
index 0000000000..a9b0751d8f
--- /dev/null
+++ b/dom/base/test/test_bug515401.html
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=515401
+-->
+<head>
+ <title>Test for Bug 515401</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <base id=basehref href="base/">
+ <base id=basehref2>
+ <base id=basetarget target="def_target">
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=515401">Mozilla Bug 515401</a>
+<a id=a href="dest.html">Simple link</a>
+<a id=awtarget target="a_target">Link with target</a>
+
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var a = $('a');
+var awtarget = $('awtarget');
+var head = document.documentElement.firstElementChild;
+
+// Test targets
+is(a.target, "def_target", "using default target");
+is(awtarget.target, "a_target", "specified target");
+$('basetarget').setAttribute("target", "new_def_target");
+is(a.target, "new_def_target", "using new default target");
+is(awtarget.target, "a_target", "still specified target");
+$('basetarget').removeAttribute("target");
+is(a.target, "", "no target");
+is(awtarget.target, "a_target", "yet still specified target");
+newbasetarget = document.createElement('base');
+newbasetarget.target = "new_target_elem";
+head.appendChild(newbasetarget);
+is(a.target, "new_target_elem", "new target element");
+is(awtarget.target, "a_target", "yet still specified target");
+newbasetarget.target = "new_target_elem_value";
+is(a.target, "new_target_elem_value", "new target element attribute");
+is(awtarget.target, "a_target", "yet still specified target");
+newbasetarget.target = "";
+is(a.target, "", "new target element no attribute");
+is(awtarget.target, "a_target", "yet still specified target");
+
+
+// link hrefs
+var basehref = $('basehref');
+var basehref2 = $('basehref2');
+var pre = "http://mochi.test:8888/tests/dom/base/test/";
+function verifyBase(base, test) {
+ if (base == "") {
+ is(document.baseURI, document.URL, "document base when " + test);
+ is(a.href, pre + "dest.html", "link href when " + test);
+ }
+ else {
+ is(document.baseURI, pre + base, "document base when " + test);
+ is(a.href, pre + base + "dest.html", "link href when " + test);
+ }
+}
+
+
+// In document base
+verifyBase("base/", "from markup");
+
+// Modify existing <base>
+basehref.href = "base2/";
+verifyBase("base2/", "modify existing");
+is(basehref.href, pre + "base2/", "HTMLBaseElement.href resolves correctly");
+
+// Modify existing <base> to absolute url
+basehref.href = "http://www.example.com/foo/bar.html";
+is(document.baseURI, "http://www.example.com/foo/bar.html", "document base when setting absolute url");
+is(a.href, "http://www.example.com/foo/dest.html", "link href when setting absolute url");
+is(basehref.href, "http://www.example.com/foo/bar.html",
+ "HTMLBaseElement.href resolves correctly when setting absolute url");
+
+// Remove href on existing element
+basehref.removeAttribute("href");
+verifyBase("", "remove href on existing element");
+
+// Create href on existing element
+basehref.href = "base3/";
+verifyBase("base3/", "create href on existing element");
+
+// Fall back to second after remove attr
+basehref2.href = "base4/";
+verifyBase("base3/", "add href on second base");
+basehref.removeAttribute("href");
+verifyBase("base4/", "fall back to second after remove attr");
+
+// Set href on existing again
+basehref.href = "base5/";
+verifyBase("base5/", "set href on existing again");
+
+// Unset href on second
+basehref2.removeAttribute("href");
+verifyBase("base5/", "unset href on second");
+
+// Insert base with href before existing
+var basehref0 = document.createElement("base");
+basehref0.href = "base6/";
+verifyBase("base5/", "nothing modified");
+head.insertBefore(basehref0, head.firstChild);
+verifyBase("base6/", "insert base with href before existing");
+
+// Insert base as grandchild of head
+var basehref3 = document.createElement("base");
+basehref3.href = "base7/";
+var tmp = document.createElement("head");
+tmp.appendChild(basehref3);
+head.insertBefore(tmp, head.firstChild);
+verifyBase("base7/", "inserted base as grandchild of head at the beginning of head");
+is(basehref3.parentNode.parentNode, head, "base got inserted correctly");
+
+// Remove secondary bases
+var tmp, tmp2;
+for (tmp = head.firstChild; tmp = tmp.nextSibling; tmp) {
+ if (tmp.localName == "base" && tmp != basehref0) {
+ tmp2 = tmp.previousSibling;
+ head.removeChild(tmp);
+ tmp = tmp2;
+ }
+ verifyBase("base7/", "remove unneeded base");
+}
+
+// Remove head
+document.documentElement.removeChild(head);
+verifyBase("", "removed head");
+
+// Insert base in body
+document.body.insertBefore(basehref3, document.body.firstChild);
+verifyBase("base7/", "inserted base in body");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug518104.html b/dom/base/test/test_bug518104.html
new file mode 100644
index 0000000000..6d557225ef
--- /dev/null
+++ b/dom/base/test/test_bug518104.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=518104
+-->
+<head>
+ <title>Test for Bug 518104</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=518104">Mozilla Bug 518104</a>
+<p id="display"></p>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 518104 **/
+// data: version at parser/htmlparser/tests/mochitest/test_bug1364399.html
+SimpleTest.waitForExplicitFinish();
+
+function done() {
+ // document.write should have gotten ignored due to the
+ // ignore-destructive-writes counter. Then document.close should
+ // have gotten ignored due to the parser still being not-script-created.
+ var iframe = document.getElementById("iframe");
+ var divs = iframe.contentWindow.document.getElementsByTagName("div").length;
+ is(divs, 2, "<div>s are still there.")
+ var ps = iframe.contentWindow.document.getElementsByTagName("p").length;
+ is(ps, 0, "<p> did not get written.")
+ SimpleTest.finish();
+}
+
+</script>
+<div id="content" style="display: none">
+ <iframe id='iframe' srcdoc="<div></div><div></div><script defer src='file_bug518104.js'></script>">
+ </iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug527896.html b/dom/base/test/test_bug527896.html
new file mode 100644
index 0000000000..582d26d24d
--- /dev/null
+++ b/dom/base/test/test_bug527896.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=527896
+-->
+<head>
+ <title>Test for Bug 527896</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 onload='done();'>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=527896">Mozilla Bug 527896</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 527896 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var docWrittenSrcExecuted = false;
+var scriptInsertedSrcExecuted = false;
+
+// the iframe test runs with the HTML5 parser
+
+var iframe = document.getElementsByTagName('iframe')[0];
+iframe.contentWindow.document.open();
+iframe.contentWindow.document.write("<!DOCTYPE html>");
+iframe.contentWindow.document.write("<body><script id =\"thescript\" src=\"data:text/javascript,parent.docWrittenSrcExecuted = true;\">");
+
+// now remove the src attribute before the end tag is parsed
+iframe.contentWindow.document.getElementById('thescript').removeAttribute('src');
+
+iframe.contentWindow.document.write("parent.ok(false, \"Content executed.\");");
+iframe.contentWindow.document.write("<\/script>");
+iframe.contentWindow.document.close();
+
+// the insertion test runs with the default HTML parser since it's in this document itself!
+
+var div = document.getElementById('content');
+var script = document.createElement('script');
+div.appendChild(script); // this shouldn't yet freeze the script node nor run it
+script.setAttribute("src", "data:text/javascript,scriptInsertedSrcExecuted = true;");
+
+todo(false, "Add SVG tests after bug 528442.");
+
+function done() {
+ ok(docWrittenSrcExecuted, "document.written src didn't execute");
+ ok(scriptInsertedSrcExecuted, "script-inserted src didn't execute");
+
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug540854.html b/dom/base/test/test_bug540854.html
new file mode 100644
index 0000000000..3baa946abd
--- /dev/null
+++ b/dom/base/test/test_bug540854.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=540854
+-->
+<head>
+ <title>Test for Bug 540854</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=540854">Mozilla Bug 540854</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 540854 **/
+
+
+ var x;
+
+ function getUTF8() {
+ return unescape(encodeURIComponent('\0foo'));
+ }
+
+ function xload() {
+ is(this.responseText, getUTF8(), "Unexpected responseText!");
+ SimpleTest.finish();
+ }
+
+ function runTest() {
+ x = new XMLHttpRequest();
+ x.open("POST", "bug540854.sjs")
+ x.onload = xload;
+ x.send(getUTF8());
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(runTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug541937.html b/dom/base/test/test_bug541937.html
new file mode 100644
index 0000000000..277b2e8e3f
--- /dev/null
+++ b/dom/base/test/test_bug541937.html
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for XHTML serializer, bug 541937</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=541937">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="testframe" src="file_bug541937.html">
+ </iframe>
+ <iframe id="testframe2" src="file_bug541937.xhtml">
+ </iframe>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function testSerializer () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder;
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("text/html");
+
+ var parser = new DOMParser();
+ var serializer = new XMLSerializer();
+
+ // with content
+ var str = '<?xml version="1.0"?><doc>\n<link xmlns="http://www.w3.org/1999/xhtml"><!-- child nodes --> \n<content xmlns=""/></link>\n</doc>';
+ var expected = '<?xml version="1.0" encoding="UTF-8"?>\n<doc>\n<link xmlns="http://www.w3.org/1999/xhtml"><!-- child nodes --> \n<content xmlns=""/></link>\n</doc>';
+
+ var doc = parser.parseFromString(str,"application/xml");
+ var result = serializer.serializeToString(doc);
+ result = result.replace(/\r\n/mg, "\n");
+ is(result, expected, "serialization of a link element inside an xml document with children");
+
+ // with only whitespaces
+ str = '<?xml version="1.0"?><doc>\n<link xmlns="http://www.w3.org/1999/xhtml"> \n </link>\n</doc>';
+ expected = '<?xml version="1.0" encoding="UTF-8"?>\n<doc>\n<link xmlns="http://www.w3.org/1999/xhtml"> \n </link>\n</doc>';
+
+ doc = parser.parseFromString(str,"application/xml");
+ result = serializer.serializeToString(doc);
+ result = result.replace(/\r\n/mg, "\n");
+ is(result, expected, "serialization of a link element with only whitespaces as content, inside an xml document");
+
+ // with only one space as content
+ str = '<?xml version="1.0"?><doc>\n<link xmlns="http://www.w3.org/1999/xhtml"> </link>\n</doc>';
+ expected = '<?xml version="1.0" encoding="UTF-8"?>\n<doc>\n<link xmlns="http://www.w3.org/1999/xhtml"> </link>\n</doc>';
+
+ doc = parser.parseFromString(str,"application/xml");
+ result = serializer.serializeToString(doc);
+ result = result.replace(/\r\n/mg, "\n");
+ is(result, expected, "serialization of a link element with only one space as content, inside an xml document");
+
+ // let's remove the content
+ str = '<?xml version="1.0"?><doc>\n<link xmlns="http://www.w3.org/1999/xhtml"> <!-- child nodes --> \ndeleted content<content xmlns=""/> </link>\n</doc>';
+ expected = '<?xml version="1.0" encoding="UTF-8"?>\n<doc>\n<link xmlns="http://www.w3.org/1999/xhtml" />\n</doc>';
+
+ doc = parser.parseFromString(str,"application/xml");
+ doc.documentElement.firstElementChild.textContent = '';
+ result = serializer.serializeToString(doc);
+ result = result.replace(/\r\n/mg, "\n");
+ is(result, expected, "serialization of a link element on which we removed dynamically the content, inside an xml document");
+
+ // with no content but an ended tag
+ str = '<?xml version="1.0"?><doc>\n<link xmlns="http://www.w3.org/1999/xhtml"></link>\n</doc>';
+ expected = '<?xml version="1.0" encoding="UTF-8"?>\n<doc>\n<link xmlns="http://www.w3.org/1999/xhtml" />\n</doc>';
+
+ doc = parser.parseFromString(str,"application/xml");
+ result = serializer.serializeToString(doc);
+ result = result.replace(/\r\n/mg, "\n");
+ is(result, expected, "serialization of a link element with no content but with an ended tag, inside an xml document");
+
+ // with no content
+ str = '<?xml version="1.0"?><doc>\n<link xmlns="http://www.w3.org/1999/xhtml"/>\n</doc>';
+ expected = '<?xml version="1.0" encoding="UTF-8"?>\n<doc>\n<link xmlns="http://www.w3.org/1999/xhtml" />\n</doc>';
+
+ doc = parser.parseFromString(str,"application/xml");
+ result = serializer.serializeToString(doc);
+ result = result.replace(/\r\n/mg, "\n");
+ is(result, expected, "serialization of a link element with no content, inside an xml document");
+
+
+ doc = $("testframe").contentDocument;
+ encoder.init(doc, "text/html", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ result = encoder.encodeToString();
+ expected = '<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n <title>Test</title>\n';
+ expected += ' <link rel=\"Top\" href=\"\"> ';
+ expected += ' </head><body>foo \n\n\n <p>Hello world</p>\n</body></html>';
+ is(result, expected, "serialization of a link element with content, inside an html document");
+
+ doc = $("testframe2").contentDocument;
+ encoder.init(doc, "application/xhtml+xml", de.OutputLFLineBreak);
+ encoder.setCharset("UTF-8");
+ result = encoder.encodeToString();
+ expected = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n';
+ expected += '<html xmlns="http://www.w3.org/1999/xhtml">\n<head>\n <meta http-equiv="content-type" content="text/html; charset=UTF-8" />\n <title>Test</title>\n';
+ expected += ' <link rel="Top" href=""> foo </link>\n';
+ expected += '\n</head>\n<body>\n <p>Hello world</p>\n</body>\n</html>';
+ is(result, expected, "serialization of a link element with content, inside an xhtml document");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testSerializer);
+
+</script>
+</pre>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug544642.html b/dom/base/test/test_bug544642.html
new file mode 100644
index 0000000000..1b9e7447d2
--- /dev/null
+++ b/dom/base/test/test_bug544642.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for bug 544642</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=544642"
+ target="_blank" >Mozilla Bug 544642</a>
+<p id="display"></p>
+<iframe id=iframe></iframe>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+var gen = runTest();
+
+addLoadEvent(function() { gen.next(); });
+
+function* runTest() {
+ var iframe = $('iframe');
+ iframe.onerror = function() { gen.next("error"); };
+ iframe.onload = function() { gen.next("load"); };
+
+ iframe.src = "data:text/plain,hello";
+ is((yield), "load", "plaintext data");
+
+ iframe.src = "file://foo/bar";
+ is((yield), "error", "file");
+
+ // We should do this test too, however it brings up a modal dialog which
+ // we can't dismiss.
+ //iframe.src = "http:////";
+ //is((yield), "error", "invalid http");
+
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug545644.html b/dom/base/test/test_bug545644.html
new file mode 100644
index 0000000000..466684c778
--- /dev/null
+++ b/dom/base/test/test_bug545644.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for HTML serializer + innerHtml, bug 545644</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=545644">Mozilla Bug </a>
+<p id="display"></p>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function testInner () {
+ var div = document.getElementById("test_inner");
+
+ try {
+ div.innerHTML = "some \u00A0 &nbsp; text";
+ div.innerHTML += "!";
+ ok(true, "innerHTML in html test ok");
+ } catch (e) {
+ ok(false, "innerHTML in html test failed, unwanted exception " + e);
+ }
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testInner);
+
+</script>
+</pre>
+<div id="test_inner"></div>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug545644.xhtml b/dom/base/test/test_bug545644.xhtml
new file mode 100644
index 0000000000..066ff31ec0
--- /dev/null
+++ b/dom/base/test/test_bug545644.xhtml
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+-->
+<head>
+ <title>Test for XHTML serializer + innerHtml, bug 545644</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=545644">Mozilla Bug </a>
+<p id="display"></p>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function testInner () {
+ var div = document.getElementById("test_inner");
+
+ try {
+ div.innerHTML = "some \u00A0 &amp;nbsp; text";
+ ok(false, "innerHTML in xhtml test failed, no exception by the parser when giving an unexpected entity"+e);
+ } catch (e) {
+ ok (true, "innerHTML in xhtml test ok");
+ }
+
+ try {
+ div.innerHTML = "some \u00A0 text";
+ div.innerHTML += "!";
+ ok (true, "innerHTML in xhtml test ok");
+ } catch (e) {
+ ok(false, "innerHTML in xhtml test failed, unexpected exception "+e);
+ }
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testInner);
+
+</script>
+</pre>
+<div id="test_inner"></div>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug548463.html b/dom/base/test/test_bug548463.html
new file mode 100644
index 0000000000..3357e4e02e
--- /dev/null
+++ b/dom/base/test/test_bug548463.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=548463
+-->
+<head>
+ <title>Test for Bug 548463</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=548463">Mozilla Bug 548463</a>
+<p id="display"></p>
+<iframe id="otherDoc"></iframe>
+<div id="content" style="display: none">
+ <p id="elem1"></p>
+ <p id="elem2"></p>
+</div>
+<div id="otherContent" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 548463 **/
+
+var otherDoc = document.getElementById("otherDoc").contentDocument;
+var content = document.getElementById("content");
+var elem1 = document.getElementById("elem1");
+var elem2 = document.getElementById("elem2");
+
+function testAdoptFromDOMNodeRemoved(nodeToAppend, nodeRemoved, nodeToAdopt)
+{
+ function reparent(event)
+ {
+ if (event.target == nodeRemoved) {
+ nodeRemoved.removeEventListener("DOMNodeRemoved", arguments.callee);
+ otherDoc.adoptNode(nodeToAdopt);
+ }
+ }
+ nodeRemoved.addEventListener("DOMNodeRemoved", reparent);
+
+ var thrown = false;
+ try {
+ document.getElementById("otherContent").appendChild(nodeToAppend);
+ }
+ catch (e) {
+ thrown = true;
+ }
+
+ ok(!thrown, "adoptNode while appending should not throw");
+}
+
+var frag = document.createDocumentFragment();
+frag.appendChild(elem1);
+frag.appendChild(elem2);
+testAdoptFromDOMNodeRemoved(frag, elem1, elem2);
+
+content.appendChild(elem1);
+testAdoptFromDOMNodeRemoved(elem1, elem1, content);
+
+content.appendChild(elem1);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug553896.xhtml b/dom/base/test/test_bug553896.xhtml
new file mode 100644
index 0000000000..e385b6aa91
--- /dev/null
+++ b/dom/base/test/test_bug553896.xhtml
@@ -0,0 +1,69 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=553896
+-->
+<head>
+ <title>Test for Bug 553896</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=553896">Mozilla Bug 553896</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+/** Test for Bug 553896 **/
+try {
+ ok(!document.createElement("foo").isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.createAttribute("foo").isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.createTextNode("foo").isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.createCDATASection("foo").isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.createProcessingInstruction("foo", "bar").isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.createComment("foo").isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.implementation.createDocumentType("html", "", "").isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+try {
+ ok(!document.createDocumentFragment().isEqualNode(null), "Node is equal to null?");
+} catch (e) {
+ ok(false, "Exception was raised.");
+}
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug557892.html b/dom/base/test/test_bug557892.html
new file mode 100644
index 0000000000..f4ff010704
--- /dev/null
+++ b/dom/base/test/test_bug557892.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=557892
+-->
+<head>
+ <title>Test for Bug 557892</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=557892">Mozilla Bug 557892</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 557892 **/
+
+SimpleTest.waitForExplicitFinish();
+
+window.open("file_bug557892.html", "", "width=100,height=100");
+
+function done() {
+ ok(true, "Should not crash");
+ setTimeout("SimpleTest.finish();", 0);
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug558726.html b/dom/base/test/test_bug558726.html
new file mode 100644
index 0000000000..7c3844b189
--- /dev/null
+++ b/dom/base/test/test_bug558726.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=558726
+-->
+<head>
+ <title>Test for Bug 558726</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=558726">Mozilla Bug 558726</a>
+<div>
+<div id="test_558726_1"><select name="selecttest"><option value="0">item 1</option></select>x<input type="button" name="test" value="test"></div>
+<div id="test_558726_2">y<input><i style="user-select: none;">z</i></div>
+</div>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 558726 **/
+
+function runTest() {
+ is(document.getElementById('test_558726_1').innerHTML, '<select name="selecttest"><option value="0">item 1</option></select>x<input type="button" name="test" value="test">','test_558726_1.innerHTML')
+ is(document.getElementById('test_558726_2').innerHTML, 'y<input><i style="user-select: none;">z</i>','test_558726_2.innerHTML')
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug559526.html b/dom/base/test/test_bug559526.html
new file mode 100644
index 0000000000..3d2b01948c
--- /dev/null
+++ b/dom/base/test/test_bug559526.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=559526
+-->
+<head>
+ <title>Test for Bug 559526</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=559526">Mozilla Bug 559526</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<div id="nodes" style="display:none">
+ <div id="child1"></div>
+ <div id="child2"></div>
+
+ <div id="child3"></div>
+ <div id="child4"></div>
+ <div id="child5"></div>
+ <div id="child6"></div>
+ <div id="child7"></div>
+ <div id="child8"></div>
+</div>
+<script type="application/javascript">
+
+/** Test for Bug 559526 **/
+
+var it;
+var recurse = false;
+var testCount = 0;
+function filter(node) {
+ if (node.id == "child3" && ! recurse) {
+ recurse = true;
+ var ex = null;
+ try {
+ var foo = it.nextNode();
+ } catch(e) {
+ ex = e;
+ }
+ ++testCount;
+ is(ex.name, "InvalidStateError", "Should have thrown an exception!");
+ is(ex.code, DOMException.INVALID_STATE_ERR, "Should have thrown an exception!");
+ recurse = false;
+ }
+ return NodeFilter.FILTER_ACCEPT;
+}
+
+(function testNodeIterator() {
+
+ it = document.createNodeIterator(
+ document.getElementById("nodes"),
+ NodeFilter.SHOW_ELEMENT,
+ filter
+ );
+ while (it.nextNode());
+})();
+
+(function testTreeWalker() {
+ it = document.createTreeWalker(
+ document.getElementById("nodes"),
+ NodeFilter.SHOW_ELEMENT,
+ filter
+ );
+ while(it.nextNode());
+
+ it = document.createTreeWalker(
+ document.getElementById("nodes"),
+ NodeFilter.SHOW_ELEMENT,
+ filter
+ );
+ it.firstChild();
+ while(it.nextSibling());
+
+ it = document.createTreeWalker(
+ document.getElementById("nodes"),
+ NodeFilter.SHOW_ELEMENT,
+ filter
+ );
+ it.lastChild();
+ while(it.previousSibling());
+})();
+
+is(testCount, 4, "Should have tests 3 filter calls!");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug560780.html b/dom/base/test/test_bug560780.html
new file mode 100644
index 0000000000..796eb72e75
--- /dev/null
+++ b/dom/base/test/test_bug560780.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=560780
+-->
+<head>
+ <title>Test for Bug 560780</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="text/javascript">
+function init() {
+ var elem = document.getElementById('body');
+ elem.addEventListener('mousedown', mousedown, true);
+}
+var seen_mousedown = 0;
+function mousedown(event) {
+ var doc = event.target.ownerDocument;
+ var win = doc.defaultView;
+ var elem = doc.getElementById('body');
+ var selection = win.getSelection();
+ if (selection.rangeCount>0) {
+ var ragne = selection.getRangeAt(0);
+ var rect = ragne.getBoundingClientRect();
+ var p = elem.parentNode.appendChild(doc.createElement('p'));
+ p.textContent = "width: " + (rect.right -rect.left);
+ }
+ ++seen_mousedown;
+}
+</script>
+
+</head>
+<body id="body">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=560780">Mozilla Bug 560780</a>
+<p id="display" style="margin:0;padding:0;border:0"><a id="testlink" href="#aaaaaaaaaaaaaaaaaaaaaa">abcdefghijklmnabcdefghijklmn</a></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+ 1.Start Minefield with New Profile.
+ 2.Select texts by alt + mouse dragging horizontaly from 'd' in the link above to far right of window.
+ 3.Click on the selected text
+ 4.Click empty area of page
+ 5.Repeat STEP 2 to 4 till browser crashes. (at least 5 times)
+
+<script type="application/javascript">
+
+/** Test for Bug 560780 **/
+
+function selectByMouseThenClick(elm,startx,starty) {
+ // select some text
+ var ctrl = !!navigator.platform.indexOf("Linux");
+ var alt = true;
+ var x = startx;
+ synthesizeMouse(elm, x, starty, { type:"mousedown", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x += 100, starty, { type:"mousemove", ctrlKey:ctrl, altKey:alt });
+ synthesizeMouse(elm, x, starty, { type:"mouseup", ctrlKey:ctrl, altKey:alt });
+
+ // click on the selection
+ synthesizeMouse(elm, startx + 10, starty + 1, {});
+
+ // click empty area of the page
+ synthesizeMouse(document.getElementById('body'), 800, 800, {});
+}
+
+function runTest() {
+ var e = document.getElementById('testlink');
+ selectByMouseThenClick(e,110,5);
+ selectByMouseThenClick(e,90,5);
+ selectByMouseThenClick(e,70,5);
+ selectByMouseThenClick(e,50,5);
+ selectByMouseThenClick(e,30,5);
+ selectByMouseThenClick(e,10,5);
+ is(seen_mousedown, 12, "got the mousedown events");
+ SimpleTest.finish();
+}
+
+function doTest() {
+ init();
+ runTest();
+}
+
+SimpleTest.waitForFocus(doTest, window);
+SimpleTest.waitForExplicitFinish();
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug562137.html b/dom/base/test/test_bug562137.html
new file mode 100644
index 0000000000..300d6f32b5
--- /dev/null
+++ b/dom/base/test/test_bug562137.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=562137
+-->
+<head>
+ <title>Test for Bug 562137</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=562137">Mozilla Bug 562137</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 562137 **/
+var myStr = "I\ufffdhave\ufffdnbsp\n";
+
+var xhr = new XMLHttpRequest();
+xhr.open("GET", "file_bug562137.txt", false);
+xhr.send();
+is(xhr.responseText, myStr);
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug562169-1.html b/dom/base/test/test_bug562169-1.html
new file mode 100644
index 0000000000..28da1421e2
--- /dev/null
+++ b/dom/base/test/test_bug562169-1.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=562169
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 562169</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=562169">Mozilla Bug 562169</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div dir="rtl" id="z"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 562169 **/
+/** Test that adding an child to an element with dir="rtl" makes the
+ child have rtl directionality, and removing the child makes it
+ go back to ltr directionality **/
+
+function checkSelector(element, expectedDir, expectedChild)
+{
+ ok(element.querySelector(":dir("+expectedDir+")") == expectedChild,
+ "direction should be " + expectedDir);
+}
+
+var x = document.createElement("div");
+var y = document.createElement("div");
+x.appendChild(y);
+checkSelector(x, "ltr", y);
+$(z).appendChild(x);
+checkSelector(x, "rtl", y);
+$(z).removeChild(x);
+checkSelector(x, "ltr", y);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug562169-2.html b/dom/base/test/test_bug562169-2.html
new file mode 100644
index 0000000000..003ed5dc02
--- /dev/null
+++ b/dom/base/test/test_bug562169-2.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=562169
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 562169</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=562169">Mozilla Bug 562169</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 562169 **/
+/** Test that a newly created element has ltr directionality **/
+
+ok(document.createElement("div").matches(":dir(ltr)"),
+ "Element should be ltr on creation");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug562652.html b/dom/base/test/test_bug562652.html
new file mode 100644
index 0000000000..e71317558d
--- /dev/null
+++ b/dom/base/test/test_bug562652.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=562652
+-->
+<head>
+ <title>Test for Bug 562652</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=562652">Mozilla Bug 562652</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="testtarget">_</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 562652 **/
+
+
+var testCount = 0;
+function createHTMLDoc() {
+ var d = document.implementation.createHTMLDocument();
+ d.body.setAttribute("id", "testtarget");
+ return d;
+}
+
+function test(d) {
+ var t = d.getElementById("testtarget");
+ d.addEventListener("DOMNodeInserted", function(e) { ++testCount; });
+ t.innerHTML = "_";
+}
+
+function runTests() {
+ test(document);
+ test(createHTMLDoc());
+ is(testCount, 2, "DOMNodeInserted should have fired 2 times!");
+ SimpleTest.finish();
+}
+
+addLoadEvent(runTests);
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug564047.html b/dom/base/test/test_bug564047.html
new file mode 100644
index 0000000000..c3321204cd
--- /dev/null
+++ b/dom/base/test/test_bug564047.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=564047
+-->
+<head>
+ <title>Test for Bug 564047</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=564047">Mozilla Bug 564047</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 564047 **/
+try {
+ document.doctype.appendChild(document.createTextNode("test"));
+ ok(false, "Should have thrown an exception");
+} catch (e) {
+ is(e.name, "HierarchyRequestError");
+ ok(e instanceof DOMException, "Should be a DOMException");
+ is(e.code, DOMException.HIERARCHY_REQUEST_ERR);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug564863-2.xhtml b/dom/base/test/test_bug564863-2.xhtml
new file mode 100644
index 0000000000..3282ccb1f4
--- /dev/null
+++ b/dom/base/test/test_bug564863-2.xhtml
@@ -0,0 +1,159 @@
+<?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=564863
+-->
+<head>
+ <title>Test for Bug 564863</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<style>
+* {
+ color: rgb(0, 0, 0);
+}
+#xul_id {
+ color: rgb(30, 30, 30);
+}
+</style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=564863">Mozilla Bug 564863</a>
+
+<!-- DOM to muck around with for tests -->
+<p id="root">
+<xul:button id="xul_id" />
+</p>
+
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+root = $('root');
+xul = root.children[0];
+
+var xul_cs = getComputedStyle(xul, "");
+
+function checkHasId(test) {
+ // Check computed style first to avoid flushes from hiding problems
+ checkHasIdNoGEBI(test);
+
+ is($("xul_id"), xul, "xul getElementById " + test);
+}
+
+function checkHasIdNoGEBI(test) {
+ const connected = test != "removed node";
+ is(xul_cs.color, connected ? "rgb(30, 30, 30)" : "", "xul color " + test);
+
+ is(xul.id, "xul_id", "xul id " + test);
+}
+
+function checkHasNoId(removed, test) {
+ // XXX This fails for some reason when this is run as a Mochitest chrome, but
+ // not when run as a Mochitest plain.
+ //is(xul_cs.color, "rgb(0, 0, 0)", "xul color " + test);
+
+ attrValue = removed ? null : "";
+
+ is(xul.id, "", "xul id " + test);
+
+ is(xul.getAttribute("id"), "", "xul getAttribute " + test);
+
+ is($("xul_id"), null, "xul getElementById " + test);
+}
+
+// Check that dynamic modifications of attribute work
+
+checkHasId("in markup");
+
+xul.id = "";
+
+checkHasNoId(false, "set to empty");
+
+xul.id = "xul_id";
+
+checkHasId("set using .id");
+
+xul.setAttribute("id", "");
+
+checkHasNoId(false, "setAttribute to empty");
+
+xul.id = "xul_id";
+
+checkHasId("set again using .id");
+
+xul.removeAttribute("id");
+
+checkHasNoId(true, "removed attribute");
+
+xul.setAttribute("id", "xul_id");
+
+checkHasId("set using setAttribute");
+
+t3 = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "button");
+t3.id = "xul_id";
+
+// Check that inserting elements before/after existing work
+
+function insertAfter(newChild, existing) {
+ existing.parentNode.insertBefore(newChild, existing.nextSibling);
+}
+function insertBefore(newChild, existing) {
+ existing.parentNode.insertBefore(newChild, existing);
+}
+function removeNode(child) {
+ child.remove();
+}
+
+insertAfter(t3, xul);
+
+checkHasId("inserted after");
+
+insertBefore(t3, xul);
+
+checkHasIdNoGEBI("inserted before");
+is($("xul_id"), t3, "xul getElementById inserted before");
+
+t3.removeAttribute("id");
+
+checkHasId("removed tx attribute");
+
+t3.setAttribute("id", "xul_id");
+
+checkHasIdNoGEBI("setAttribute before");
+is($("xul_id"), t3, "xul getElementById setAttribute before");
+
+removeNode(t3);
+
+checkHasId("removed temporaries");
+
+removeNode(xul);
+
+checkHasIdNoGEBI("removed node");
+
+// Re-add the id inside a mutation event on a XUL element
+is($("xul_id"), null, "no xul");
+xul = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "button");
+xul.id = "xul_id";
+root.appendChild(xul);
+is($("xul_id"), xul, "new xul is set up");
+mutateFired = false;
+xul.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, xul, "target is xul");
+ is(xul.getAttribute("id"), "", "xul no longer has id attr");
+ is(xul.id, "", "xul no longer has id");
+ xul.id = "other_xul_id";
+ mutateFired = true;
+}, {once: true});
+xul.removeAttribute("id");
+ok(mutateFired, "mutation event fired");
+is($("xul_id"), null, "xul_id was removed from table");
+is($("other_xul_id"), xul, "other_xul_id was added");
+removeNode(xul);
+is($("other_xul_id"), null, "other_xul_id was removed");
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug564863.xhtml b/dom/base/test/test_bug564863.xhtml
new file mode 100644
index 0000000000..18a934b1d5
--- /dev/null
+++ b/dom/base/test/test_bug564863.xhtml
@@ -0,0 +1,305 @@
+<!DOCTYPE html [
+<!ATTLIST ns:x id ID #REQUIRED>
+<!ATTLIST ns2:x id_2 ID #REQUIRED>
+]>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:ns="urn:namespace"
+ xmlns:ns2="urn:namespace">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=564863
+-->
+<head>
+ <title>Test for Bug 564863</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<style>
+* {
+ color: rgb(0, 0, 0);
+}
+#div_id {
+ color: rgb(10, 10, 10);
+}
+#a_id {
+ color: rgb(20, 20, 20);
+}
+#svg_id {
+ color: rgb(40, 40, 40);
+}
+#ns_id {
+ color: rgb(50, 50, 50);
+}
+#ns2_id {
+ color: rgb(60, 60, 60);
+}
+</style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=564863">Mozilla Bug 564863</a>
+<!-- Elements to ensure we have nodeinfos with id-attribute set -->
+<div><ns:x id="ns-holder"/><ns2:x id_2="ns2-holder"/></div>
+
+<!-- DOM to muck around with for tests -->
+<p id="root">
+<div id="div_id" />
+<a id="a_id" />
+<svg:svg><svg:g id="svg_id" /></svg:svg>
+<ns:x id="ns_id" />
+</p>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+root = $('root');
+div = root.children[0];
+a = root.children[1];
+svg = root.children[2].firstChild;
+nsx = root.children[3];
+
+var div_cs = getComputedStyle(div, "");
+var a_cs = getComputedStyle(a, "");
+var svg_cs = getComputedStyle(svg, "");
+var nsx_cs = getComputedStyle(nsx, "");
+
+function checkHasId(test) {
+ // Check computed style first to avoid flushes from hiding problems
+ checkHasIdNoGEBI(test);
+
+ is($("div_id"), div, "div getElementById " + test);
+ is($("a_id"), a, "a getElementById " + test);
+ is($("svg_id"), svg, "svg getElementById " + test);
+ is($("ns_id"), nsx, "ns getElementById " + test);
+}
+
+function checkHasIdNoGEBI(test) {
+ const connected = test != "removed node";
+ is(div_cs.color, connected ? "rgb(10, 10, 10)" : "", "div color " + test);
+ is(a_cs.color, connected ? "rgb(20, 20, 20)" : "", "a color " + test);
+ is(svg_cs.color, connected ? "rgb(40, 40, 40)" : "", "svg color " + test);
+ is(nsx_cs.color, connected ? "rgb(50, 50, 50)" : "", "nsx color " + test);
+
+ is(div.id, "div_id", "div id " + test);
+ is(a.id, "a_id", "a id " + test);
+ is(svg.id, "svg_id", "svg id " + test);
+ is (nsx.getAttribute("id"), "ns_id", "ns id " + test);
+}
+
+function checkHasNoId(removed, test) {
+ is(div_cs.color, "rgb(0, 0, 0)", "div color " + test);
+ is(a_cs.color, "rgb(0, 0, 0)", "a color " + test);
+ is(svg_cs.color, "rgb(0, 0, 0)", "svg color " + test);
+ is(nsx_cs.color, "rgb(0, 0, 0)", "nsx color " + test);
+
+ attrValue = removed ? null : "";
+
+ is(div.id, "", "div id " + test);
+ is(a.id, "", "a id " + test);
+ is(svg.id, "", "svg id " + test);
+
+ is(div.getAttribute("id"), attrValue, "div getAttribute " + test);
+ is(a.getAttribute("id"), attrValue, "a getAttribute " + test);
+ is(svg.getAttribute("id"), attrValue, "svg getAttribute " + test);
+ is(nsx.getAttribute("id"), attrValue, "ns getAttribute " + test);
+
+ is($("div_id"), null, "div getElementById " + test);
+ is($("a_id"), null, "a getElementById " + test);
+ is($("svg_id"), null, "svg getElementById " + test);
+ is($("ns_id"), null, "ns getElementById " + test);
+}
+
+// Check that dynamic modifications of attribute work
+
+checkHasId("in markup");
+
+div.id = "";
+a.id = "";
+svg.id = "";
+nsx.setAttribute("id", "");
+
+checkHasNoId(false, "set to empty");
+
+div.id = "div_id";
+a.id = "a_id";
+svg.id = "svg_id";
+nsx.setAttribute("id", "ns_id");
+
+checkHasId("set using .id");
+
+div.setAttribute("id", "");
+a.setAttribute("id", "");
+svg.setAttribute("id", "");
+nsx.setAttribute("id", "");
+
+checkHasNoId(false, "setAttribute to empty");
+
+div.id = "div_id";
+a.id = "a_id";
+svg.id = "svg_id";
+nsx.setAttribute("id", "ns_id");
+
+checkHasId("set again using .id");
+
+div.removeAttribute("id");
+a.removeAttribute("id");
+svg.removeAttribute("id");
+nsx.removeAttribute("id");
+
+checkHasNoId(true, "removed attribute");
+
+div.setAttribute("id", "div_id");
+a.setAttribute("id", "a_id");
+svg.setAttribute("id", "svg_id");
+nsx.setAttribute("id", "ns_id");
+
+checkHasId("set using setAttribute");
+
+t1 = document.createElement("div");
+t1.id = "div_id";
+t2 = document.createElement("a");
+t2.id = "a_id";
+t4 = document.createElementNS("http://www.w3.org/2000/svg", "g");
+t4.id = "svg_id";
+t5 = document.createElementNS("urn:namespace", "ns:x");
+t5.setAttribute("id", "ns_id");
+
+// Check that inserting elements before/after existing work
+
+function insertAfter(newChild, existing) {
+ existing.parentNode.insertBefore(newChild, existing.nextSibling);
+}
+function insertBefore(newChild, existing) {
+ existing.parentNode.insertBefore(newChild, existing);
+}
+function removeNode(child) {
+ child.remove();
+}
+
+insertAfter(t1, div);
+insertAfter(t2, a);
+insertAfter(t4, svg);
+insertAfter(t5, nsx);
+
+checkHasId("inserted after");
+
+insertBefore(t1, div);
+insertBefore(t2, a);
+insertBefore(t4, svg);
+insertBefore(t5, nsx);
+
+checkHasIdNoGEBI("inserted before");
+is($("div_id"), t1, "div getElementById inserted before");
+is($("a_id"), t2, "a getElementById inserted before");
+is($("svg_id"), t4, "svg getElementById inserted before");
+is($("ns_id"), t5, "ns getElementById inserted before");
+
+t1.removeAttribute("id");
+t2.removeAttribute("id");
+t4.removeAttribute("id");
+t5.removeAttribute("id");
+
+checkHasId("removed tx attribute");
+
+t1.setAttribute("id", "div_id");
+t2.setAttribute("id", "a_id");
+t4.setAttribute("id", "svg_id");
+t5.setAttribute("id", "ns_id");
+
+checkHasIdNoGEBI("setAttribute before");
+is($("div_id"), t1, "div getElementById setAttribute before");
+is($("a_id"), t2, "a getElementById setAttribute before");
+is($("svg_id"), t4, "svg getElementById setAttribute before");
+is($("ns_id"), t5, "ns getElementById setAttribute before");
+
+removeNode(t1);
+removeNode(t2);
+removeNode(t4);
+removeNode(t5);
+
+checkHasId("removed temporaries");
+
+removeNode(div);
+removeNode(a);
+removeNode(svg);
+removeNode(nsx);
+
+checkHasIdNoGEBI("removed node");
+
+// Check that removing an element during UnsetAttr works
+is(div.id, "div_id", "div still has id set");
+var mutateFired = false;
+root.appendChild(div);
+div.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, div, "target is div");
+ is(div.id, "", "div no longer has id");
+ is(div.getAttribute("id"), null, "div no longer has id attr");
+ removeNode(div);
+ is(div.parentNode, null, "div was removed");
+ mutateFired = true;
+}, {once: true});
+div.removeAttribute("id");
+ok(mutateFired, "mutation event fired");
+
+// Check same for XML elements
+is(nsx.getAttribute("id"), "ns_id", "nsx still has id set");
+mutateFired = false;
+root.appendChild(nsx);
+nsx.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, nsx, "target is nsx");
+ is(nsx.getAttribute("id"), null, "nsx no longer has id attr");
+ removeNode(nsx);
+ is(nsx.parentNode, null, "nsx was removed");
+ mutateFired = true;
+}, {once: true});
+nsx.removeAttribute("id");
+ok(mutateFired, "mutation event fired");
+
+
+// Re-add the id inside a mutation event on a XML element
+is($("ns_id"), null, "no nsx");
+is($("ns2_id"), null, "no nsx");
+nsx = document.createElementNS("urn:namespace", "ns:x");
+nsx.setAttribute("id", "ns_id");
+root.appendChild(nsx);
+is($("ns_id"), nsx, "new nsx is set up");
+mutateFired = false;
+nsx.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, nsx, "target is nsx");
+ is(nsx.getAttribute("id"), null, "nsx no longer has id attr");
+ nsx.setAttribute("id", "other_id");
+ mutateFired = true;
+}, {once: true});
+nsx.removeAttribute("id");
+ok(mutateFired, "mutation event fired");
+is($("ns_id"), null, "ns_id was removed from table");
+is($("other_id"), nsx, "other_id was added");
+removeNode(nsx);
+is($("other_id"), null, "other_id was removed");
+
+// Re-add the id inside a mutation event on a HTML element
+is($("div_id"), null, "no div");
+div = document.createElement("div");
+div.id = "div_id";
+root.appendChild(div);
+is($("div_id"), div, "new div is set up");
+mutateFired = false;
+div.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, div, "target is div");
+ is(div.getAttribute("id"), null, "div no longer has id attr");
+ is(div.id, "", "div no longer has id");
+ div.id = "other_div_id";
+ mutateFired = true;
+}, {once: true});
+div.removeAttribute("id");
+ok(mutateFired, "mutation event fired");
+is($("div_id"), null, "div_id was removed from table");
+is($("other_div_id"), div, "other_div_id was added");
+removeNode(div);
+is($("other_div_id"), null, "other_div_id was removed");
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug567350.html b/dom/base/test/test_bug567350.html
new file mode 100644
index 0000000000..14a8687af9
--- /dev/null
+++ b/dom/base/test/test_bug567350.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=567350
+-->
+<head>
+ <title>Test for Bug 567350</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=567350">Mozilla Bug 567350</a>
+<p id="display"><span style="color: blue;"></span></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 567350 **/
+is(getComputedStyle(document.getElementById("display").firstChild).color,
+ "rgb(0, 0, 255)");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug574596.html b/dom/base/test/test_bug574596.html
new file mode 100644
index 0000000000..d9f6832bb4
--- /dev/null
+++ b/dom/base/test/test_bug574596.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=574596
+-->
+<head>
+ <title>Test for Bug 574596</title>
+ <script 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="https://bugzilla.mozilla.org/show_bug.cgi?id=574596">Mozilla Bug 574596</a>
+<style type="text/css">
+#link1 a { user-select:none; }
+</style>
+<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
+<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 574596 **/
+
+function ignoreFunc(actualData, expectedData) {
+ return true;
+}
+
+var dragLinkText = [[
+ { type:"text/x-moz-url", data:"", eqTest:ignoreFunc },
+ { type:"text/x-moz-url-data", data:"http://www.mozilla.org/" },
+ { type:"text/x-moz-url-desc", data:"link1" },
+ { type:"text/uri-list", data:"http://www.mozilla.org/" },
+ { type:"text/_moz_htmlcontext", data:"", eqTest:ignoreFunc },
+ { type:"text/_moz_htmlinfo", data:"", eqTest:ignoreFunc },
+ { type:"text/html", data:'<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>' },
+ { type:"text/plain", data:"http://www.mozilla.org/" }
+]];
+
+
+function dumpTransfer(dataTransfer,expect) {
+ dataTransfer = SpecialPowers.wrap(dataTransfer);
+ dtData = dataTransfer.mozItemCount + "items:\n";
+ for (var i = 0; i < dataTransfer.mozItemCount; i++) {
+ var dtTypes = dataTransfer.mozTypesAt(i);
+ for (var j = 0; j < dtTypes.length; j++) {
+ var actualData = dataTransfer.mozGetDataAt(dtTypes[j],i)
+ if (expect && expect[i] && expect[i][j]) {
+ if (expect[i][j].eqTest)
+ dtData += expect[i][j].eqTest(actualData,expect[i][j].data) ? "ok" : "fail";
+ else
+ dtData += (actualData == expect[i][j].data) ? "ok" : "fail";
+ }
+ dtData += "["+i+"]" + "["+j+"]: " + '"' + dtTypes[j] + '" "' + actualData + '"\n';
+ }
+ }
+ alert(dtData);
+}
+
+async function runTest() {
+ var result = await synthesizePlainDragAndCancel(
+ {
+ srcElement: $('link1').firstChild,
+ finalY: -10, // Avoid clicking the link
+ },
+ dragLinkText);
+ ok(result === true, "Drag user-select:none link (#link1)");
+ // if (result) dumpTransfer(result,dragLinkText);
+
+ dragLinkText[0][2].data = "link2";
+ dragLinkText[0][6].data = '<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>'
+ var result = await synthesizePlainDragAndCancel(
+ {
+ srcElement: $('link2').firstChild,
+ finalY: -10, // Avoid clicking the link
+ },
+ dragLinkText);
+ ok(result === true, "Drag link (#link2)");
+ // if (result) dumpTransfer(result,dragLinkText);
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTest);
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug578096.html b/dom/base/test/test_bug578096.html
new file mode 100644
index 0000000000..22df0757ca
--- /dev/null
+++ b/dom/base/test/test_bug578096.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=578096
+-->
+<head>
+ <title>Test for Bug 578096</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=578096">Mozilla Bug 578096</a>
+<p id="display"></p>
+<div id="content">
+ <input type="file" id="file" onchange="fireXHR()">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var url = SimpleTest.getTestFileURL("bug578096LoadChromeScript.js");
+var script = SpecialPowers.loadChromeScript(url);
+
+script.addMessageListener("file.created", function (message) {
+ SpecialPowers.wrap(document.getElementById('file')).mozSetFileArray([message]);
+
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function(event) {
+ if (xhr.readyState == 4) {
+ script.sendAsyncMessage("file.remove", {});
+ }
+ }
+
+ xhr.open('POST', window.location, true);
+ xhr.send(document.getElementById('file').files[0]);
+});
+
+script.addMessageListener("file.removed", function (message) {
+ ok(true, "We didn't throw! Yay!");
+ script.destroy();
+ SimpleTest.finish();
+});
+
+script.sendAsyncMessage("file.create", {});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug585978.html b/dom/base/test/test_bug585978.html
new file mode 100644
index 0000000000..e00cb8d84c
--- /dev/null
+++ b/dom/base/test/test_bug585978.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=585978
+-->
+<head>
+ <title>Test for Bug 585978</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=585978">Mozilla Bug 585978</a>
+
+<script type="application/javascript">
+
+/* Test that if we have a unicode character in the middle of an ascii string,
+ the unicode character survives translation into and out of a text node. */
+
+for (let i = 0; i < 128; i++) {
+ let node = document.createTextNode('');
+ let str = '';
+ for (let j = 0; j < i; j++) {
+ str += 'a';
+ }
+ str += '\uA0A9'
+ node.data = str;
+
+ for (let j = 0; j < 32; j++) {
+ is(node.data, str);
+
+ str += 'b';
+ node.appendData('b');
+ }
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug587931.html b/dom/base/test/test_bug587931.html
new file mode 100644
index 0000000000..0a4b84dec7
--- /dev/null
+++ b/dom/base/test/test_bug587931.html
@@ -0,0 +1,102 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=587931
+-->
+<head>
+ <title>Test for Bug 587931</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=587931">Mozilla Bug 587931</a>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 587931 **/
+SimpleTest.waitForExplicitFinish();
+var afterCount = 0;
+var lastBeforeExecute = null;
+var expectedCurrentScriptInAfterScriptExecute = null;
+function verifyScript(n) {
+ var curr = document.currentScript;
+ is(curr, document.getElementById(n), "correct script (" + n + ")");
+ is(lastBeforeExecute, curr, "correct beforescript (" + n + ")");
+ document.addEventListener("afterscriptexecute", function(event) {
+ afterCount++;
+ lastBeforeExecute = null;
+ is(event.target, curr, "correct afterscript (" + n + ")");
+ is(document.currentScript, expectedCurrentScriptInAfterScriptExecute,
+ "document.currentScript in afterscriptexecute(" + n + ")");
+ document.removeEventListener("afterscriptexecute", arguments.callee);
+ });
+}
+document.onbeforescriptexecute = function(event) {
+ lastBeforeExecute = event.target;
+};
+
+window.addEventListener("load", function() {
+ is(afterCount, 4, "correct number of afterscriptexecute");
+ SimpleTest.finish();
+});
+</script>
+</pre>
+<!-- Test parser inserted scripts -->
+<script id="parse-inline">
+verifyScript("parse-inline");
+</script>
+<script id="parse-ext" src="data:text/plain,verifyScript('parse-ext');"></script>
+
+<!-- Test DOM inserted scripts -->
+<script>
+var s = document.createElement("script");
+s.textContent = "verifyScript('dom-inline');";
+s.id = "dom-inline";
+expectedCurrentScriptInAfterScriptExecute = document.currentScript;
+document.body.appendChild(s);
+expectedCurrentScriptInAfterScriptExecute = null;
+
+s = document.createElement("script");
+s.src = "data:text/plain,verifyScript('dom-ext');";
+s.id = "dom-ext";
+document.body.appendChild(s);
+</script>
+
+<!-- Test cancel using beforescriptexecute -->
+<script onbeforescriptexecute="return false;"
+ onafterescriptexecute="window.firedAfterScriptExecuteForCancel = true;">
+ok(false, "should have been canceled");
+</script>
+<script>
+isnot(window.firedAfterScriptExecuteForCancel, true, "onafterscriptexecute executed");
+</script>
+
+<!-- Test cancel using beforescriptexecute for external -->
+<script onbeforescriptexecute="return false;"
+ onafterescriptexecute="window.extFiredAfterScriptExecuteForCancel = true;"
+ onload="window.extFiredLoadForCancel = true;"
+ src="data:text/plain,ok(false, 'should have been canceled');">
+</script>
+<script>
+isnot(window.extFiredAfterScriptExecuteForCancel, true, "onafterscriptexecute executed");
+is(extFiredLoadForCancel, true, "onload executed");
+</script>
+
+<!-- Test that all events fire -->
+<script onbeforescriptexecute="window.beforeDidExecute = true;"
+ onafterscriptexecute="window.afterDidExecute = true;"
+ onload="window.loadDidExecute = true"
+ onerror="window.errorDidExecute = true"
+ src="data:text/plain,
+is(window.beforeDidExecute, true, 'onbeforescriptexecute executed');
+isnot(window.afterDidExecute, true, 'onafterscriptexecute executed');
+isnot(window.loadDidExecute, true, 'onload executed');
+isnot(window.errorDidExecute, true, 'onerror executed');
+">
+</script>
+<script>
+is(afterDidExecute, true, "onafterscriptexecute executed");
+is(loadDidExecute, true, "onload executed");
+isnot(window.errorDidExecute, true, "onerror executed");
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug588990.html b/dom/base/test/test_bug588990.html
new file mode 100644
index 0000000000..ac7051270e
--- /dev/null
+++ b/dom/base/test/test_bug588990.html
@@ -0,0 +1,332 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=588990
+-->
+<head>
+ <title>Test for Bug 588990</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=588990">Mozilla Bug 588990</a>
+<!-- DOM to muck around with for tests -->
+<p id="root">
+<img name="n1">
+<img name="n2">
+<img name="n2">
+<img name="n3">
+<img name="n3">
+<img name="n3">
+</p>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+root = $('root');
+i1_1 = root.children[0];
+i2_1 = root.children[1];
+i2_2 = root.children[2];
+i3_1 = root.children[3];
+i3_2 = root.children[4];
+i3_3 = root.children[5];
+
+function checkHasName(test) {
+ // Check name first to avoid flushes from hiding problems
+ checkHasNameNoDocProp(test);
+
+ is(document.n1, i1_1, "i1_1 doc.name " + test);
+ is(document.n2[0], i2_1, "i2_1 doc.name " + test);
+ is(document.n2[1], i2_2, "i2_2 doc.name " + test);
+ is(document.n2.length, 2, "doc.name.length " + test);
+ is(document.n3[0], i3_1, "i3_1 doc.name " + test);
+ is(document.n3[1], i3_2, "i3_2 doc.name " + test);
+ is(document.n3[2], i3_3, "i3_3 doc.name " + test);
+ is(document.n3.length, 3, "doc.name.length " + test);
+}
+
+function checkHasNameNoDocProp(test) {
+ is(i1_1.name, "n1", "i1_1 name " + test);
+ is(i2_1.name, "n2", "i2_1 name " + test);
+ is(i2_2.name, "n2", "i2_2 name " + test);
+ is(i3_1.name, "n3", "i3_1 name " + test);
+ is(i3_2.name, "n3", "i3_2 name " + test);
+ is(i3_3.name, "n3", "i3_3 name " + test);
+}
+
+function checkHasNoName(removed, test) {
+ is(i1_1.name, "", "i1_1 name " + test);
+ is(i2_1.name, "", "i2_1 name " + test);
+ is(i2_2.name, "", "i2_2 name " + test);
+ is(i3_1.name, "", "i3_1 name " + test);
+ is(i3_2.name, "", "i3_2 name " + test);
+ is(i3_3.name, "", "i3_3 name " + test);
+
+ var attrValue = removed ? null : "";
+ is(i1_1.getAttribute("name"), attrValue, "i1_1 getAttribute " + test);
+ is(i2_1.getAttribute("name"), attrValue, "i2_1 getAttribute " + test);
+ is(i2_2.getAttribute("name"), attrValue, "i2_2 getAttribute " + test);
+ is(i3_1.getAttribute("name"), attrValue, "i3_1 getAttribute " + test);
+ is(i3_2.getAttribute("name"), attrValue, "i3_2 getAttribute " + test);
+ is(i3_3.getAttribute("name"), attrValue, "i3_3 getAttribute " + test);
+
+ is(document.n1, undefined, "doc.n1 " + test);
+ is(document.n2, undefined, "doc.n2 " + test);
+ is(document.n3, undefined, "doc.n3 " + test);
+}
+
+// Check that dynamic modifications of attribute work
+
+checkHasName("in markup");
+
+i1_1.name = "";
+i2_1.name = "";
+i2_2.name = "";
+i3_1.name = "";
+i3_2.name = "";
+i3_3.name = "";
+
+checkHasNoName(false, "set to empty");
+
+i1_1.name = "n1";
+i2_1.name = "n2";
+i2_2.name = "n2";
+i3_1.name = "n3";
+i3_2.name = "n3";
+i3_3.name = "n3";
+
+checkHasName("set using .name");
+
+i1_1.setAttribute("name", "");
+i2_1.setAttribute("name", "");
+i2_2.setAttribute("name", "");
+i3_1.setAttribute("name", "");
+i3_2.setAttribute("name", "");
+i3_3.setAttribute("name", "");
+
+checkHasNoName(false, "setAttribute to empty");
+
+i1_1.name = "n1";
+i2_1.name = "n2";
+i2_2.name = "n2";
+i3_1.name = "n3";
+i3_2.name = "n3";
+i3_3.name = "n3";
+
+checkHasName("set again using .name");
+
+i1_1.removeAttribute("name");
+i2_1.removeAttribute("name");
+i2_2.removeAttribute("name");
+i3_1.removeAttribute("name");
+i3_2.removeAttribute("name");
+i3_3.removeAttribute("name");
+
+checkHasNoName(true, "removed attribute");
+
+i1_1.setAttribute("name", "n1");
+i2_1.setAttribute("name", "n2");
+i2_2.setAttribute("name", "n2");
+i3_1.setAttribute("name", "n3");
+i3_2.setAttribute("name", "n3");
+i3_3.setAttribute("name", "n3");
+
+checkHasName("set using setAttribute");
+
+t1 = document.createElement("img");
+t1.name = "n1";
+t2 = document.createElement("img");
+t2.name = "n2";
+t3 = document.createElement("img");
+t3.name = "n2";
+t4 = document.createElement("img");
+t4.name = "n3";
+t5 = document.createElement("img");
+t5.name = "n3";
+t6 = document.createElement("img");
+t6.name = "n3";
+
+// Check that inserting elements before/after existing work
+
+function insertAfter(newChild, existing) {
+ existing.parentNode.insertBefore(newChild, existing.nextSibling);
+}
+function insertBefore(newChild, existing) {
+ existing.parentNode.insertBefore(newChild, existing);
+}
+function removeNode(child) {
+ child.remove();
+}
+
+insertAfter(t1, i1_1);
+insertAfter(t2, i2_1);
+insertAfter(t3, i2_2);
+insertAfter(t4, i3_1);
+insertAfter(t5, i3_2);
+insertAfter(t6, i3_3);
+
+checkHasNameNoDocProp("inserted after");
+is(document.n1[0], i1_1, "i1_1 doc.name inserted after");
+is(document.n1[1], t1, "t1 doc.name inserted after");
+is(document.n1.length, 2, "doc.name1.length inserted after");
+is(document.n2[0], i2_1, "i2_1 doc.name inserted after");
+todo_is(document.n2[1], t2, "This is where t2 should show up. The elements in here should be in order-in-document rather than order-of-insertion");
+is(document.n2[1], i2_2, "i2_2 doc.name inserted after");
+is(document.n2[2], t2, "t2 doc.name inserted after");
+is(document.n2[3], t3, "t3 doc.name inserted after");
+is(document.n2.length, 4, "doc.name2.length inserted after");
+is(document.n3[0], i3_1, "i3_1 doc.name inserted after");
+is(document.n3[1], i3_2, "i3_3 doc.name inserted after");
+is(document.n3[2], i3_3, "i3_2 doc.name inserted after");
+is(document.n3[3], t4, "t4 doc.name inserted after");
+is(document.n3[4], t5, "t5 doc.name inserted after");
+is(document.n3[5], t6, "t6 doc.name inserted after");
+is(document.n3.length, 6, "doc.name3.length inserted after");
+
+
+insertBefore(t1, i1_1);
+insertBefore(t2, i2_1);
+insertBefore(t3, i2_2);
+insertBefore(t4, i3_1);
+insertBefore(t5, i3_2);
+insertBefore(t6, i3_3);
+
+checkHasNameNoDocProp("inserted before");
+is(document.n1[0], i1_1, "i1_1 doc.name inserted before");
+is(document.n1[1], t1, "t1 doc.name inserted before");
+is(document.n1.length, 2, "doc.name1.length inserted before");
+is(document.n2[0], i2_1, "i2_1 doc.name inserted before");
+is(document.n2[1], i2_2, "i2_2 doc.name inserted before");
+is(document.n2[2], t2, "t2 doc.name inserted before");
+is(document.n2[3], t3, "t3 doc.name inserted before");
+is(document.n2.length, 4, "doc.name2.length inserted before");
+is(document.n3[0], i3_1, "i3_1 doc.name inserted before");
+is(document.n3[1], i3_2, "i3_3 doc.name inserted before");
+is(document.n3[2], i3_3, "i3_2 doc.name inserted before");
+is(document.n3[3], t4, "t4 doc.name inserted before");
+is(document.n3[4], t5, "t5 doc.name inserted before");
+is(document.n3[5], t6, "t6 doc.name inserted before");
+is(document.n3.length, 6, "doc.name3.length inserted before");
+
+t1.removeAttribute("name");
+t2.removeAttribute("name");
+t3.removeAttribute("name");
+t4.removeAttribute("name");
+t5.removeAttribute("name");
+t6.removeAttribute("name");
+
+checkHasName("removed tx attribute");
+
+t1.setAttribute("name", "n1");
+t2.setAttribute("name", "n2");
+t3.setAttribute("name", "n2");
+t4.setAttribute("name", "n3");
+t5.setAttribute("name", "n3");
+t6.setAttribute("name", "n3");
+
+checkHasNameNoDocProp("inserted before");
+is(document.n1[0], i1_1, "i1_1 doc.name inserted before");
+is(document.n1[1], t1, "t1 doc.name inserted before");
+is(document.n1.length, 2, "doc.name1.length inserted before");
+is(document.n2[0], i2_1, "i2_1 doc.name inserted before");
+is(document.n2[1], i2_2, "i2_2 doc.name inserted before");
+is(document.n2[2], t2, "t2 doc.name inserted before");
+is(document.n2[3], t3, "t3 doc.name inserted before");
+is(document.n2.length, 4, "doc.name2.length inserted before");
+is(document.n3[0], i3_1, "i3_1 doc.name inserted before");
+is(document.n3[1], i3_2, "i3_3 doc.name inserted before");
+is(document.n3[2], i3_3, "i3_2 doc.name inserted before");
+is(document.n3[3], t4, "t4 doc.name inserted before");
+is(document.n3[4], t5, "t5 doc.name inserted before");
+is(document.n3[5], t6, "t6 doc.name inserted before");
+is(document.n3.length, 6, "doc.name3.length inserted before");
+
+removeNode(t1);
+removeNode(t2);
+removeNode(t3);
+removeNode(t4);
+removeNode(t5);
+removeNode(t6);
+
+checkHasName("removed temporaries");
+
+removeNode(i1_1);
+removeNode(i2_1);
+removeNode(i2_2);
+removeNode(i3_1);
+removeNode(i3_2);
+removeNode(i3_3);
+
+checkHasNameNoDocProp("removed node");
+
+// Check that removing an element during UnsetAttr works
+is(i1_1.name, "n1", "i1_1 has name set");
+var mutateFired = false;
+root.appendChild(i1_1);
+i1_1.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, i1_1, "target is i1_1");
+ is(i1_1.name, "", "i1_1 no longer has name");
+ is(i1_1.getAttribute("name"), null, "i1_1 no longer has name attr");
+ removeNode(i1_1);
+ is(i1_1.parentNode, null, "i1_1 was removed");
+ mutateFired = true;
+}, {once: true});
+i1_1.removeAttribute("name");
+ok(mutateFired, "mutation event fired");
+SpecialPowers.gc();
+
+// Check that removing an element during SetAttr works
+i2_1.name = "";
+mutateFired = false;
+root.appendChild(i2_1);
+i2_1.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, i2_1, "target is i2_1");
+ is(i2_1.name, "n2", "i2_1 no longer has name");
+ is(i2_1.getAttribute("name"), "n2", "i2_1 no longer has name attr");
+ removeNode(i2_1);
+ is(i2_1.parentNode, null, "i2_1 was removed");
+ mutateFired = true;
+}, {once: true});
+i2_1.name = "n2";
+ok(mutateFired, "mutation event fired");
+SpecialPowers.gc();
+
+// Re-add the name inside a mutation event on a HTML element
+is(i2_2.name, "n2", "i2_2 has name set");
+root.appendChild(i2_2);
+mutateFired = false;
+root.appendChild(i2_2);
+i2_2.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, i2_2, "target is i2_2");
+ is(i2_2.name, "", "i2_2 no longer has name");
+ is(i2_2.getAttribute("name"), "", "i2_2 has empty name attr");
+ i2_2.name = "n2";
+ mutateFired = true;
+}, {once: true});
+i2_2.name = "";
+ok(mutateFired, "mutation event fired");
+is(document.n2, i2_2, "named was readded during mutation");
+removeNode(i2_2);
+SpecialPowers.gc();
+
+// Re-remove the name inside a mutation event on a HTML element
+i3_1.name = "";
+root.appendChild(i3_1);
+mutateFired = false;
+root.appendChild(i3_1);
+i3_1.addEventListener("DOMAttrModified", function(e) {
+ is(e.target, i3_1, "target is i3_1");
+ is(i3_1.name, "n3", "i3_1 no longer has name");
+ is(i3_1.getAttribute("name"), "n3", "i3_1 has empty name attr");
+ i3_1.removeAttribute("name");
+ mutateFired = true;
+}, {once: true});
+i3_1.name = "n3";
+ok(mutateFired, "mutation event fired");
+is(document.n3, undefined, "named was readded during mutation");
+removeNode(i3_1);
+SpecialPowers.gc();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug590812.html b/dom/base/test/test_bug590812.html
new file mode 100644
index 0000000000..d96da7b538
--- /dev/null
+++ b/dom/base/test/test_bug590812.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for XML pretty printing, bug 590812</title>
+ <script src="/tests/SimpleTest/SimpleTest.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=590812">Mozilla Bug 590812</a>
+<p id="display"></p>
+<iframe id=iframe></iframe>
+<iframe src="file_bug590812-ref.xhtml"></iframe>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+
+add_task(async function start() {
+ var noxul = "https://sub1.test1.example.com:443";
+ var yesxul = "https://example.org:443"
+
+ await SpecialPowers.pushPermissions([
+ { type: "allowXULXBL", allow: false, context: noxul },
+ { type: "allowXULXBL", allow: true, context: yesxul }
+ ]);
+
+ var path = "/tests/dom/base/test/file_bug590812.xml";
+ var iframe = $('iframe');
+ iframe.src = noxul + path;
+ await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true}));
+ let sNoXUL = await snapshotWindow(window.frames[0], false);
+
+ iframe.src = yesxul + path;
+ await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true}));
+ let sWithXUL = await snapshotWindow(window.frames[0], false);
+
+ let sRef = await snapshotWindow(window.frames[1], false);
+
+ let res;
+ ok(compareSnapshots(sNoXUL, sRef, true)[0],
+ "noxul domain same as ref");
+ ok(compareSnapshots(sWithXUL, sRef, true)[0],
+ "xul supporting domain same as ref");
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug590870.html b/dom/base/test/test_bug590870.html
new file mode 100644
index 0000000000..29269ee609
--- /dev/null
+++ b/dom/base/test/test_bug590870.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for creating XUL elements, bug 590870</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=590870">Mozilla Bug 590870</a>
+<p id="display"></p>
+<iframe id=iframe></iframe>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+
+add_task(async function start() {
+ var noxul = "https://sub1.test1.example.com:443";
+ var yesxul = "https://example.org:443"
+
+ await SpecialPowers.pushPermissions([
+ { type: "allowXULXBL", allow: false, context: noxul },
+ { type: "allowXULXBL", allow: true, context: yesxul }
+ ]);
+
+ var path = "/tests/dom/base/test/file_bug590870.html";
+ var iframe = $('iframe');
+
+ iframe.src = noxul + path;
+ await new Promise(resolve => window.addEventListener("message", event => {
+ is(event.data, true, "shouldn't be able to create XUL elements");
+ resolve();
+ }, { once: true } ));
+
+ iframe.src = yesxul + path;
+ await new Promise(resolve => window.addEventListener("message", event => {
+ is(event.data, false, "should be able to create XUL elements");
+ resolve();
+ }, { once: true } ));
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug592366.html b/dom/base/test/test_bug592366.html
new file mode 100644
index 0000000000..1e217b5358
--- /dev/null
+++ b/dom/base/test/test_bug592366.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=592366
+-->
+<head>
+ <title>Test for Bug 592366</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=592366">Mozilla Bug 592366</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+<iframe></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 592366 **/
+
+var gExecuted = false;
+
+function hitEventLoop(times, next)
+{
+ if (times == 0) {
+ next();
+ return;
+ }
+
+ SimpleTest.executeSoon(function() {
+ hitEventLoop(times - 1, next);
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ var s = document.createElement("script");
+ s.src = "data:text/javascript,parent.gExecuted=true;";
+
+ var iframes = document.getElementsByTagName("iframe");
+
+ iframes[0].contentDocument.body.appendChild(s);
+ iframes[1].contentDocument.body.appendChild(s);
+
+ // It seems to work with 1 event loop hit locally but using 2 given that it
+ // was hsivonen advice.
+ hitEventLoop(2, function() {
+ ok(!gExecuted, "The scripts should not have been executed");
+ SimpleTest.finish();
+ });
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug592829.html b/dom/base/test/test_bug592829.html
new file mode 100644
index 0000000000..cb078f8bce
--- /dev/null
+++ b/dom/base/test/test_bug592829.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=592829
+-->
+<head>
+ <title>Test for Bug 592829</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=592829">Mozilla Bug 592829</a>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 592829 **/
+
+// NOTE! It's imperative that we don't call .init() here. Otherwise we're not
+// testing what happens if parsing fails.
+// If we ever change how DOMParser initilization works, just update this code
+// to create a DOMParser which is not allowed to parse XUL.
+
+var isXUL = true;
+var parser = SpecialPowers.getNoXULDOMParser();
+ok(parser, "Should get a parser!");
+
+try {
+ var x = parser
+ .parseFromString('<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>', "text/xml");
+ isXUL = x.documentElement.namespaceURI ==
+ "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+}
+catch (ex) {
+ isXUL = false;
+}
+
+is(isXUL, false, "We didn't create XUL and we didn't crash!");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug597345.html b/dom/base/test/test_bug597345.html
new file mode 100644
index 0000000000..21cd73a29a
--- /dev/null
+++ b/dom/base/test/test_bug597345.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=597345
+-->
+<head>
+ <title>Test for Bug 597345</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=597345">Mozilla Bug 597345</a>
+<pre id="test">
+ <!-- We want no spaces inside span id="target". The 'stray' close comment at
+ the end of that span needs to be there! -->
+ <span id="target"><script
+ src="script-1_bug597345.sjs"></script><script
+ charset="ISO-5559-1" src="script-2_bug597345.js"></script>--></span>
+<script type="application/javascript">
+
+/** Test for Bug 597345 **/
+is($("target").textContent, "R\u00e4ksm\u00f6rg\u00e5s",
+ "script-2 should be decoded as UTF-8");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug599295.html b/dom/base/test/test_bug599295.html
new file mode 100644
index 0000000000..ba807a5b7e
--- /dev/null
+++ b/dom/base/test/test_bug599295.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=599295
+-->
+<head>
+ <title>Test for Bug 599295</title>
+ <script 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="https://bugzilla.mozilla.org/show_bug.cgi?id=599295">Mozilla Bug 599295</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 599295 **/
+
+/* Do not allow a response to a CONNECT method, used to establish an
+ SSL tunnel over an HTTP proxy, to contain a redirect */
+
+function runTest() {
+ /* Previously, necko would allow a 302 as part of a CONNECT response
+ if the LOAD_DOCUMENT_URI flag was set and the original document
+ URI had not yet been changed. */
+
+ SpecialPowers.loadChannelAndReturnStatus("https://redirproxy.example.com/test",
+ true)
+ .then(function({status, httpStatus}) {
+ /* testing here that the redirect was not followed. If it was followed
+ we would see a http status of 200 and status of NS_OK */
+
+ is(httpStatus, 302, "http status 302");
+ is(status, SpecialPowers.Cr.NS_ERROR_CONNECTION_REFUSED,
+ "raised refused");
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTest);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug599588.html b/dom/base/test/test_bug599588.html
new file mode 100644
index 0000000000..043f48687a
--- /dev/null
+++ b/dom/base/test/test_bug599588.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=599588
+-->
+<head>
+ <title>Test for Bug 599588</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=599588">Mozilla Bug 599588</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 599588 **/
+
+var div = document.createElement("div");
+div.innerHTML = "\u003Cscript>ok(false, 'Scripts created by innerHTML should not run.');\u003C/script>";
+document.body.appendChild(div);
+
+var contextualFragmentRan = false;
+
+var range = document.createRange();
+range.selectNode(document.body);
+var fragment = range.createContextualFragment("\u003Cscript>contextualFragmentRan = true;\u003C/script>");
+document.body.appendChild(fragment);
+
+ok(contextualFragmentRan, "Script from createContextualFragment should have run.");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug601803.html b/dom/base/test/test_bug601803.html
new file mode 100644
index 0000000000..5f4e765ab3
--- /dev/null
+++ b/dom/base/test/test_bug601803.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=601803
+-->
+<head>
+ <title>Test for Bug 601803</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=601803">Mozilla Bug 601803</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe id="frame"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 601803 **/
+SimpleTest.waitForExplicitFinish();
+
+window.onmessage = function (event) {
+ is(event.data, false, "Shouldn't throw when adopting a node cross-compartment");
+ SimpleTest.finish();
+}
+
+document.getElementById("frame").src = "http://example.org/tests/dom/base/test/file_bug601803a.html";
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug602838.html b/dom/base/test/test_bug602838.html
new file mode 100644
index 0000000000..661a6410e8
--- /dev/null
+++ b/dom/base/test/test_bug602838.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=602838
+-->
+<head>
+ <title>Test for Bug 602838</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=602838">Mozilla Bug 602838</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script id=withasync async></script>
+<script id=withoutasync></script>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 602838 **/
+SimpleTest.waitForExplicitFinish();
+var firstRan = false;
+var asyncRan = false;
+
+var withoutasync = document.getElementById("withoutasync");
+ok(withoutasync.async, "When a script loses parser-insertedness, it should become async.");
+
+var withasync = document.getElementById("withasync");
+ok(withasync.async, "A script with the async content attribute should have the DOM attribute reporting true.");
+withasync.removeAttribute("async");
+ok(!withasync.async, "Should be able to remove asyncness from a script that had the async content attribute when losing parser-insertedness by removing the content attribute.");
+
+var s = document.createElement("script");
+ok(s.async, "Script-created scripts should default to .async=true");
+ok(!s.hasAttribute("async"), "Script-created scripts should not have the async content attribute by default.");
+s.removeAttribute("async");
+ok(s.async, "Removing a non-existing content-attribute should not have an effect on the forced async DOM property.");
+s.setAttribute("async", "");
+ok(s.async, "The async DOM property should still be true.");
+s.removeAttribute("async");
+ok(!s.async, "When a previously present async content attribute is removed, the DOM property should become false.");
+s.src = "script_bug602838.sjs";
+document.body.appendChild(s);
+
+s = document.createElement("script");
+s.src = "data:text/javascript,ok(firstRan, 'The first script should have run'); SimpleTest.finish();";
+s.async = false;
+ok(!s.async, "Setting the async DOM property to false should turned of forcing async to true.");
+document.body.appendChild(s);
+
+function unblock() {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "script_bug602838.sjs?unblock");
+ xhr.send();
+}
+
+s = document.createElement("script");
+s.src = "data:text/javascript,ok(!firstRan, 'Non-async should not have run yet.'); asyncRan = true; unblock();";
+document.body.appendChild(s);
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug604592.html b/dom/base/test/test_bug604592.html
new file mode 100644
index 0000000000..e92ee8acde
--- /dev/null
+++ b/dom/base/test/test_bug604592.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=604592
+-->
+<head>
+ <title>Test for Bug 604592</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=604592">Mozilla Bug 604592</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 604592 **/
+function testInStrictMode() {
+ "use strict";
+ try {
+ document.body.prefix = "foo";
+ ok(false, "Should not have reached this point");
+ } catch (e) {
+ ok(e instanceof TypeError, "Expected a TypeError");
+ }
+}
+
+testInStrictMode();
+document.body.prefix = "foo";
+ok(document.body.prefix === null,
+ "Expected strictly equal to null, got " + document.body.prefix);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug604660.html b/dom/base/test/test_bug604660.html
new file mode 100644
index 0000000000..dd5c8be0d9
--- /dev/null
+++ b/dom/base/test/test_bug604660.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=604660
+-->
+<head>
+ <title>Test for Bug 604660</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=604660">Mozilla Bug 604660</a>
+<script>
+SimpleTest.waitForExplicitFinish();
+var asyncState = false;
+var scriptState = 0;
+
+function scriptRan(num) {
+ ++scriptState;
+ is(scriptState, num, "Scripts ran in the wrong sequence.");
+}
+
+function asyncRan() {
+ asyncState = true;
+}
+
+</script>
+<p id="display"><iframe src="file_bug604660-1.xml" onload="iframeloaded()";></iframe></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var xlstProcessorState = false;
+
+function xsltProcessorCreatedScriptRan() {
+ xlstProcessorState = true;
+}
+
+function iframeloaded() {
+ ok(asyncState, "Async script should have run.");
+ is(scriptState, 5, "Five scripts should have run.");
+
+ var processor = new XSLTProcessor();
+
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4) {
+ processor.importStylesheet(this.responseXML);
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4) {
+ var doc = processor.transformToDocument(this.responseXML);
+ var target = document.getElementById("display");
+ target.appendChild(doc.documentElement.firstChild);
+ ok(!xlstProcessorState, "Scripts created by transformToDocument should not run.");
+
+ var fragment = processor.transformToFragment(this.responseXML, document);
+ target.appendChild(fragment.firstChild.firstChild);
+ ok(xlstProcessorState, "Scripts created by transformToFragment should run.");
+
+ SimpleTest.finish();
+ }
+ }
+ xhr.open("GET", "file_bug604660-5.xml");
+ xhr.send();
+ }
+ }
+ xhr.open("GET", "file_bug604660-6.xsl");
+ xhr.send();
+}
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug605982.html b/dom/base/test/test_bug605982.html
new file mode 100644
index 0000000000..abd9dc9c32
--- /dev/null
+++ b/dom/base/test/test_bug605982.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=605982
+-->
+<head>
+ <title>Test for Bug 605982</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=605982">Mozilla Bug 605982</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 605982 **/
+
+var elmt = document.createElement("div");
+
+var caught = false;
+try {
+ elmt.matches("!!");
+} catch(e) {
+ ok(e.name == "SyntaxError", "Error should be SyntaxError");
+ ok(e.code == DOMException.SYNTAX_ERR, "Error code should be SYNTAX_ERR");
+ caught = true;
+}
+ok(caught, "An exception should have been thrown");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug606729.html b/dom/base/test/test_bug606729.html
new file mode 100644
index 0000000000..1f9e54d8ec
--- /dev/null
+++ b/dom/base/test/test_bug606729.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=606729
+-->
+<head>
+ <title>Test for Bug 606729</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=606729">Mozilla Bug 606729</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script>
+ SimpleTest.waitForExplicitFinish();
+ var events = 0;
+ var expectedEvents = 2;
+ function eventFired() {
+ ++events;
+ if (events == expectedEvents) {
+ SimpleTest.finish();
+ }
+ }
+</script>
+<script
+ src="data:"
+ onerror="ok(true, 'Script with src=data: should fire onerror.');
+ eventFired();"
+ onload="ok(false, 'Script with src=data: should not fire onload.');
+ eventFired();"
+>
+ok(false, "Script with src=data: should not run textContent.");
+</script>
+<script
+ src="bogus:"
+ onerror="ok(true, 'Script with src=bogus: should fire onerror.');
+ eventFired();"
+ onload="ok(false, 'Script with src=bogus: should not fire onload.');
+ eventFired();"
+>
+ok(false, "Script with src=bogus: should not run textContent.");
+</script>
+</pre>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_bug614058.html b/dom/base/test/test_bug614058.html
new file mode 100644
index 0000000000..61ca86005e
--- /dev/null
+++ b/dom/base/test/test_bug614058.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=614058
+-->
+<head>
+ <title>Test for Bug 614058</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=614058">Mozilla Bug 614058</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 614058 **/
+var f1 = document.createDocumentFragment();
+f2 = f1.cloneNode(true);
+f1.appendChild(document.createElement("foo"));
+is(f1.isEqualNode(f2), false, "Fragments have different kids!");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug622088.html b/dom/base/test/test_bug622088.html
new file mode 100644
index 0000000000..bedb192bfc
--- /dev/null
+++ b/dom/base/test/test_bug622088.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 622088 - Test that XHR gives the referrer corresponding to the dynamic script context.</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=622088">Mozilla Bug 622088</a>
+<pre id="test">
+
+<iframe id='iframe' src='file_bug622088_inner.html'></iframe>
+
+<iframe id='dataWindow' srcdoc="<html><head>
+<script>function getXHRObject() { return new XMLHttpRequest(); }</script>
+</head><body onload='parent.dataWindowLoaded()'>Hello!!</body></html>"></iframe>
+
+<script class="testbody" type="application/javascript">
+
+// Bug 622088 - Test that XHR gives the referrer corresponding to the
+// dynamic script context.
+
+const kOriginalLocation = location.href;
+
+SimpleTest.waitForExplicitFinish();
+
+var innerFinishedLoading = false;
+function innerLoaded(inner) {
+ // Here, we're being called through inner's onload handler, so our referrer
+ // should be inner's URL.
+ var referrer = inner.doXHR();
+ is (referrer, String(inner.document.location), 'Expected inner frame location');
+
+ // Now change the location of the inner frame. This should be reflected in
+ // the XHR's referrer.
+ inner.history.pushState('', '', Math.random());
+ referrer = inner.doXHR();
+ is (referrer, String(inner.document.location), 'Expected inner frame location after pushstate');
+
+ innerFinishedLoading = true;
+}
+
+var dataWindowFinishedLoading = false;
+function dataWindowLoaded() {
+ dataWindowFinishedLoading = true;
+}
+
+function callXHR() {
+ if (innerFinishedLoading && dataWindowFinishedLoading) {
+ var inner = document.getElementById('iframe').contentWindow;
+ var referrer = inner.doXHR();
+ is (referrer, String(inner.document.location),
+ 'Expected inner frame location when called from outer frame.');
+
+ var referrer = inner.doXHR(new XMLHttpRequest());
+ is (referrer, String(document.location),
+ "Expected outer frame location when called with outer's XHR object.");
+
+ // Now do a request within the inner window using an XMLHttpRequest
+ // retrieved from a data: URI. The referrer should be this window, not the
+ // data: URI.
+ var dataWindow = document.getElementById('dataWindow').contentWindow;
+ var referrer = inner.doXHR(dataWindow.getXHRObject());
+ is (referrer, String(document.location),
+ "Expected outer frame location when called with data's XHR object.");
+
+ // Now do that test again, but after having changed the outer window's URI.
+ // This currently fails, due to basically bug 631949. It's not even clear
+ // what the right behavior is. So marking as a todo for now.
+ history.replaceState('', '', Math.random());
+
+ var referrer = inner.doXHR(dataWindow.getXHRObject());
+ todo_is (referrer, String(document.location),
+ "Expected outer frame location when called with data's XHR object " +
+ "after replaceState.");
+
+ // In case you're temped, you probably don't want to do history.pushState
+ // here and test again with the outer frame. Calling pushState on the
+ // outer frame messes up Mochitest in subtle ways.
+
+ history.replaceState('', '', kOriginalLocation);
+ SimpleTest.finish();
+ }
+ else {
+ // ugh.
+ setTimeout(callXHR, 0);
+ }
+}
+
+callXHR();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug622117.html b/dom/base/test/test_bug622117.html
new file mode 100644
index 0000000000..8e829afc6a
--- /dev/null
+++ b/dom/base/test/test_bug622117.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=622117
+-->
+<head>
+ <title>Test for Bug 622117</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" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=622117">Mozilla Bug 622117</a>
+<p id="display">
+ <iframe id="testframe"
+ srcdoc="<a href='PASS.html' onclick='throw 1'>Click me</a>">
+ </iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 622117 **/
+SimpleTest.waitForExplicitFinish();
+
+const { testframe } = document.all;
+
+waitUntilApzStable().then(async () => {
+ testframe.onload = function() {
+ is(this.contentDocument.documentElement.innerText, "PASS", "Should have loaded link");
+ SimpleTest.finish();
+ };
+
+ is(testframe.contentDocument.readyState, "complete", "iframe is not loaded yet?");
+
+ var win = testframe.contentWindow;
+ await SimpleTest.promiseFocus(win);
+
+ var a = win.document.getElementsByTagName("a")[0];
+ synthesizeMouseAtCenter(a, {}, win);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug622246.html b/dom/base/test/test_bug622246.html
new file mode 100644
index 0000000000..a4349afb68
--- /dev/null
+++ b/dom/base/test/test_bug622246.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=622246
+-->
+<head>
+ <title>Test for Bug 622246</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" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=622246">Mozilla Bug 622246</a>
+<p id="display">
+ <iframe id="testframe"
+ srcdoc="<span onclick='this.parentNode.removeChild(this)'><a href='PASS.html'>Click me</a></span>">
+ </iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 622246 **/
+SimpleTest.waitForExplicitFinish();
+
+const { testframe } = document.all;
+
+waitUntilApzStable().then(async () => {
+ testframe.onload = function() {
+ is(this.contentDocument.documentElement.innerText, "PASS", "Should have loaded link");
+ SimpleTest.finish();
+ };
+
+ is(testframe.contentDocument.readyState, "complete", "iframe is not loaded yet?");
+
+ var win = testframe.contentWindow;
+ await SimpleTest.promiseFocus(win);
+
+ var a = win.document.getElementsByTagName("a")[0];
+ synthesizeMouseAtCenter(a, {}, win);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug625722.html b/dom/base/test/test_bug625722.html
new file mode 100644
index 0000000000..502427134c
--- /dev/null
+++ b/dom/base/test/test_bug625722.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=625722
+-->
+<head>
+ <title>Test for Bug 625722</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=625722">Mozilla Bug 625722</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <span id=root><span id=A><span id=A1></span></span><span id=B></span></span>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 625722 **/
+
+function testNodeFilter(n) {
+ if (n.id == 'A' || n.id == 'A1')
+ return NodeFilter.FILTER_SKIP;
+ return NodeFilter.FILTER_ACCEPT;
+}
+
+tw = document.createTreeWalker(document.getElementById("root"),
+ NodeFilter.SHOW_ELEMENT,
+ testNodeFilter);
+
+node = tw.firstChild();
+is(node.id, 'B', "First accepted child of root not B");
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug626262.html b/dom/base/test/test_bug626262.html
new file mode 100644
index 0000000000..04af972040
--- /dev/null
+++ b/dom/base/test/test_bug626262.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=626262
+-->
+<head>
+ <title>Test for Bug 626262</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=626262">Mozilla Bug 626262</a>
+<p id="display"><iframe id="f" srcdoc="1"></iframe></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 626262 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ var iframe = document.getElementById("f");
+ var frameDoc = iframe.contentDocument;
+ var parent = frameDoc.createElementNS("http://www.w3.org/1999/xhtml", "div");
+
+ function a()
+ {
+ window.removeEventListener("DOMNodeRemoved", arguments.callee);
+ document.adoptNode(parent);
+ }
+
+ var text = document.createTextNode(" ");
+ document.documentElement.appendChild(text);
+
+ var thrown = false;
+ try {
+ window.addEventListener("DOMNodeRemoved", a);
+ parent.appendChild(text);
+ }
+ catch (e) {
+ thrown = true;
+ }
+
+ ok(!thrown, "changing ownerDocument during adoptNode should not throw");
+
+ SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug628938.html b/dom/base/test/test_bug628938.html
new file mode 100644
index 0000000000..a4f069468b
--- /dev/null
+++ b/dom/base/test/test_bug628938.html
@@ -0,0 +1,239 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=628938
+-->
+<head>
+ <title>Test for Bug 628938</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=628938">Mozilla Bug 628938</a>
+<p id="display"></p>
+<foo id="content" style="display: none">
+ <div><div>foo</div></div>
+ <span> bar </span>
+ <div>tulip<span>bar</span></div>
+ <span></span>
+ <div>foo</div>
+ <span></span>
+ <div>bar</div>
+ <span></span>
+ <div>foobar</div>
+</foo>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 628938 **/
+
+var gResults = [];
+var gIdx = 0;
+
+function walkTree(walker)
+{
+ if(walker.firstChild()) {
+ do {
+ if (walker.currentNode.nodeType == Node.ELEMENT_NODE) {
+ ok(gResults[gIdx][0], "current node should be an element");
+ is(walker.currentNode.nodeName, gResults[gIdx][1],
+ "current node name should be " + gResults[gIdx][1]);
+ } else {
+ ok(!gResults[gIdx][0], "current node shouldn't be an element");
+ is(walker.currentNode.nodeValue, gResults[gIdx][1],
+ "current node value should be " + gResults[gIdx][1]);
+ }
+ gIdx++;
+ // Recursively walk the rest of the sub-tree.
+ walkTree(walker);
+ } while(walker.nextSibling());
+
+ // don't forget to return the treewalker to it's previous state
+ // before exiting the function
+ walker.parentNode();
+ }
+}
+
+function regularWalk()
+{
+ gResults = [
+ [ false, "\n " ],
+ [ true, "DIV" ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ false, "\n " ],
+ [ true, "SPAN" ],
+ [ false, " bar " ],
+ [ false, "\n " ],
+ [ true, "DIV" ],
+ [ false, "tulip" ],
+ [ true, "SPAN" ],
+ [ false, "bar" ],
+ [ false, "\n " ],
+ [ true, "SPAN" ],
+ [ false, "\n " ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ false, "\n " ],
+ [ true, "SPAN" ],
+ [ false, "\n " ],
+ [ true, "DIV" ],
+ [ false, "bar" ],
+ [ false, "\n " ],
+ [ true, "SPAN" ],
+ [ false, "\n " ],
+ [ true, "DIV" ],
+ [ false, "foobar" ],
+ [ false, "\n" ],
+ ];
+ var walker = document.createTreeWalker(document.getElementById('content'),
+ NodeFilter.SHOW_ALL, null);
+
+ walkTree(walker);
+
+ gIdx = 0;
+}
+
+function noWhiteSpaceWalk()
+{
+ gResults = [
+ [ true, "DIV" ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ true, "SPAN" ],
+ [ false, " bar " ],
+ [ true, "DIV" ],
+ [ false, "tulip" ],
+ [ true, "SPAN" ],
+ [ false, "bar" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ [ false, "bar" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ [ false, "foobar" ],
+ ];
+ var walker = document.createTreeWalker(document.getElementById('content'),
+ NodeFilter.SHOW_ALL,
+ {
+ acceptNode(node) {
+ if (node.nodeType == Node.TEXT_NODE &&
+ !(/[^\t\n\r ]/.test(node.nodeValue)))
+ return NodeFilter.FILTER_REJECT;
+ return NodeFilter.FILTER_ACCEPT;
+ }
+ });
+
+ walkTree(walker);
+
+ gIdx = 0;
+}
+
+function onlyElementsWalk()
+{
+ gResults = [
+ [ true, "DIV" ],
+ [ true, "DIV" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ [ true, "SPAN" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ ];
+ var walker = document.createTreeWalker(document.getElementById('content'),
+ NodeFilter.SHOW_ELEMENT, null);
+
+ walkTree(walker);
+
+ gIdx = 0;
+}
+
+function onlyDivSubTreeWalk()
+{
+ gResults = [
+ [ true, "DIV" ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ true, "DIV" ],
+ [ false, "tulip" ],
+ [ true, "SPAN" ],
+ [ false, "bar" ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ true, "DIV" ],
+ [ false, "bar" ],
+ [ true, "DIV" ],
+ [ false, "foobar" ],
+ ];
+ var walker = document.createTreeWalker(document.getElementById('content'),
+ NodeFilter.SHOW_ALL,
+ {
+ acceptNode(node) {
+ if (node.nodeType == Node.TEXT_NODE &&
+ !(/[^\t\n\r ]/.test(node.nodeValue)))
+ return NodeFilter.FILTER_REJECT;
+
+ while (node) {
+ if (node.nodeName == "DIV")
+ return NodeFilter.FILTER_ACCEPT;
+ node = node.parentNode;
+ }
+ return NodeFilter.FILTER_SKIP;
+ }
+ });
+
+ walkTree(walker);
+
+ gIdx = 0;
+}
+
+function onlyDivDataWalk()
+{
+ gResults = [
+ [ true, "DIV" ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ true, "DIV" ],
+ [ false, "tulip" ],
+ [ true, "SPAN" ],
+ [ true, "DIV" ],
+ [ false, "foo" ],
+ [ true, "DIV" ],
+ [ false, "bar" ],
+ [ true, "DIV" ],
+ [ false, "foobar" ],
+ ];
+ var walker = document.createTreeWalker(document.getElementById('content'),
+ NodeFilter.SHOW_ALL,
+ {
+ acceptNode(node) {
+ if (node.nodeName == "DIV" ||
+ (node.parentNode &&
+ node.parentNode.nodeName == "DIV"))
+ return NodeFilter.FILTER_ACCEPT;
+ return NodeFilter.FILTER_SKIP;
+ }
+ });
+
+ walkTree(walker);
+
+ gIdx = 0;
+}
+
+regularWalk();
+noWhiteSpaceWalk();
+onlyElementsWalk();
+onlyDivSubTreeWalk();
+onlyDivDataWalk();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug631615.html b/dom/base/test/test_bug631615.html
new file mode 100644
index 0000000000..b78295eb34
--- /dev/null
+++ b/dom/base/test/test_bug631615.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=631615
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 631615</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=631615"
+ >Mozilla Bug 631615</a>
+<pre id="monitor"></pre>
+<script>
+function doTest() {
+ var monitor = document.getElementById("monitor");
+ var html = document.documentElement;
+ var results;
+
+ try {
+ results = "return: " + html.matches("[test!='']:sizzle") + "\n";
+ } catch (e) {
+ results = "throws: " + e + "\n";
+ }
+
+ monitor.appendChild(document.createTextNode(results));
+ is(results.slice(0, 6), "throws", "looking for an exception");
+}
+
+SimpleTest.runTestExpectingConsoleMessages(doTest, [{
+ forbid: true,
+ message: /An invalid or illegal string was specified/
+}]);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug638112.html b/dom/base/test/test_bug638112.html
new file mode 100644
index 0000000000..8bc645f077
--- /dev/null
+++ b/dom/base/test/test_bug638112.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=638112
+https://bugzilla.mozilla.org/show_bug.cgi?id=796850
+-->
+<head>
+ <title>Test for Bug 638112</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=638112">Mozilla Bug 638112</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=796850">Mozilla Bug 796850</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="text/javascript">
+
+/** Test for Bug 638112, revised for Bug 796850 **/
+
+/* Bug 796850 changed the type of statusText to ByteString. As a result it is
+ * now considered to be raw 8 bit encoded rather than UTF8.
+ */
+
+function run_test() {
+ var req = new XMLHttpRequest();
+ req.open("GET", "bug638112.sjs", false);
+ req.send(null);
+ var statusText = req.statusText;
+
+ is(statusText, "Information Sans-Autorit\u00E9", "");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(run_test);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug647518.html b/dom/base/test/test_bug647518.html
new file mode 100644
index 0000000000..0dc88d9ee1
--- /dev/null
+++ b/dom/base/test/test_bug647518.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=647518
+-->
+<head>
+ <title>Test for Bug 647518</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=647518">Mozilla Bug 647518</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 647518 **/
+SimpleTest.waitForExplicitFinish();
+var counter = 3;
+
+var called = false;
+var handle1 = window.requestAnimationFrame(function() {
+ called = true;
+});
+ok(handle1 > 0, "Should get back a nonzero handle");
+
+function checker() {
+ --counter;
+ if (counter == 0) {
+ is(called, false, "Canceled callback should not have been called");
+ SimpleTest.finish();
+ } else {
+ window.requestAnimationFrame(checker);
+ }
+}
+window.requestAnimationFrame(checker);
+window.cancelAnimationFrame(handle1);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug650001.html b/dom/base/test/test_bug650001.html
new file mode 100644
index 0000000000..14cbb4ae41
--- /dev/null
+++ b/dom/base/test/test_bug650001.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650001
+-->
+<head>
+ <title>Test for Bug 650001</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=650001">Mozilla Bug 650001</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650001 **/
+
+var svg = '<svg><style xml:lang="en" xlink:href="foo" xmlns="bar" xmlns:link="qux">&lt;&gt;</style><script>&lt;&gt;<\/script></svg>';
+var div = document.getElementById("content");
+div.innerHTML = svg;
+is(div.innerHTML, svg, "Unexpected serialization.");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug650776.html b/dom/base/test/test_bug650776.html
new file mode 100644
index 0000000000..163da5e4c0
--- /dev/null
+++ b/dom/base/test/test_bug650776.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650776
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650776</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=650776">Mozilla Bug 650776</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650776 **/
+
+var u = SpecialPowers.Ci.nsIParserUtils;
+var s = SpecialPowers.ParserUtils;
+
+// Basic sanity
+is(s.sanitize("foo", 0), "<html><head></head><body>foo</body></html>", "Wrong sanitizer result 1");
+// Scripts get removed
+is(s.sanitize("<script>\u003c/script>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 2");
+// Event handlers get removed
+is(s.sanitize("<a onclick='boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 3");
+// By default, styles are removed
+is(s.sanitize("<style>p { color: red; }</style><p style='background-color: blue;'></p>", 0), "<html><head></head><body><p></p></body></html>", "Wrong sanitizer result 4");
+// Can allow styles
+is(s.sanitize("<style>p { color: red; }</style><p style='background-color: blue;'></p>", u.SanitizerAllowStyle), '<html><head><style>p { color: red; }</style></head><body><p style="background-color: blue;"></p></body></html>', "Wrong sanitizer result 5");
+// -moz-binding used to get dropped, but no longer does.
+is(s.sanitize("<style>p { color: red; -moz-binding: url(foo); }</style><p style='background-color: blue; -moz-binding: url(foo);'></p>", u.SanitizerAllowStyle), '<html><head><style>p { color: red; -moz-binding: url(foo); }</style></head><body><p style="background-color: blue; -moz-binding: url(foo);"></p></body></html>', "Wrong sanitizer result 6");
+// Various cid: embeds only cases
+is(s.sanitize("<img src='foo.html'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 7");
+is(s.sanitize("<img src='cid:foo'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img src="cid:foo"></body></html>', "Wrong sanitizer result 8");
+is(s.sanitize("<img src='data:image/png,'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 9");
+is(s.sanitize("<img src='http://mochi.test/'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><img></body></html>', "Wrong sanitizer result 10");
+is(s.sanitize("<a href='http://mochi.test/'></a>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><a href="http://mochi.test/"></a></body></html>', "Wrong sanitizer result 11");
+is(s.sanitize("<body background='http://mochi.test/'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 12");
+is(s.sanitize("<body background='cid:foo'>", u.SanitizerCidEmbedsOnly), '<html><head></head><body background="cid:foo"></body></html>', "Wrong sanitizer result 13");
+is(s.sanitize("<svg></svg>", u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 14");
+is(s.sanitize("<math definitionURL='cid:foo' altimg='cid:foo'></math>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><math></math></body></html>', "Wrong sanitizer result 14");
+is(s.sanitize("<video><source src='http://mochi.test/'></video>", u.SanitizerCidEmbedsOnly), '<html><head></head><body><video controls="controls"><source></video></body></html>', "Wrong sanitizer result 15");
+is(s.sanitize("<style></style>", u.SanitizerAllowStyle | u.SanitizerCidEmbedsOnly), '<html><head></head><body></body></html>', "Wrong sanitizer result 16");
+// Dangerous links
+is(s.sanitize("<a href='javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 17");
+is(s.sanitize("<a href='JavaScript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 18");
+is(s.sanitize("<a href=' javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 19");
+is(s.sanitize("<a href='\njavascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 20");
+is(s.sanitize("<a href='\fjavascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 21");
+is(s.sanitize("<a href='\u00A0javascript:boom()'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 22");
+is(s.sanitize("<a href='foo.html'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 23");
+// Comments
+is(s.sanitize("<!-- foo -->", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 24");
+is(s.sanitize("<!-- foo -->", u.SanitizerAllowComments), "<!-- foo -->\n<html><head></head><body></body></html>", "Wrong sanitizer result 25");
+// noscript
+is(s.sanitize("<body><noscript><p class=bar>foo</p></noscript>", 0), '<html><head></head><body><noscript><p class="bar">foo</p></noscript></body></html>', "Wrong sanitizer result 26");
+// dangerous elements
+is(s.sanitize("<iframe></iframe>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 27");
+is(s.sanitize("<object></object>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 28");
+is(s.sanitize("<embed>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 29");
+// presentationalism
+is(s.sanitize("<font></font>", 0), "<html><head></head><body><font></font></body></html>", "Wrong sanitizer result 30");
+is(s.sanitize("<center></center>", 0), "<html><head></head><body><center></center></body></html>", "Wrong sanitizer result 31");
+is(s.sanitize("<div align=center></div>", 0), '<html><head></head><body><div align="center"></div></body></html>', "Wrong sanitizer result 32");
+is(s.sanitize("<table><tr><td bgcolor=#FFFFFF>", 0), '<html><head></head><body><table><tbody><tr><td bgcolor="#FFFFFF"></td></tr></tbody></table></body></html>', "Wrong sanitizer result 33");
+is(s.sanitize("<font></font>", u.SanitizerDropNonCSSPresentation), "<html><head></head><body></body></html>", "Wrong sanitizer result 34");
+is(s.sanitize("<center></center>", u.SanitizerDropNonCSSPresentation), "<html><head></head><body></body></html>", "Wrong sanitizer result 35");
+is(s.sanitize("<div align=center></div>", u.SanitizerDropNonCSSPresentation), '<html><head></head><body><div></div></body></html>', "Wrong sanitizer result 36");
+is(s.sanitize("<table><tr><td bgcolor=#FFFFFF>", u.SanitizerDropNonCSSPresentation), '<html><head></head><body><table><tbody><tr><td></td></tr></tbody></table></body></html>', "Wrong sanitizer result 37");
+// metadata
+is(s.sanitize("<meta charset=utf-7>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 38");
+is(s.sanitize("<meta http-equiv=content-type content='text/html; charset=utf-7'>", 0), "<html><head></head><body></body></html>", "Wrong sanitizer result 39");
+is(s.sanitize("<meta itemprop=foo content=bar>", 0), '<html><head><meta itemprop="foo" content="bar"></head><body></body></html>', "Wrong sanitizer result 40");
+is(s.sanitize("<link rel=whatever href=http://mochi.test/ >", 0), '<html><head></head><body></body></html>', "Wrong sanitizer result 41");
+is(s.sanitize("<link itemprop=foo href=http://mochi.test/ >", 0), '<html><head><link itemprop="foo" href="http://mochi.test/"></head><body></body></html>', "Wrong sanitizer result 42");
+is(s.sanitize("<link rel=stylesheet itemprop=foo href=http://mochi.test/ >", 0), '<html><head><link itemprop="foo" href="http://mochi.test/"></head><body></body></html>', "Wrong sanitizer result 43");
+is(s.sanitize("<meta name=foo content=bar>", 0), '<html><head><meta name="foo" content="bar"></head><body></body></html>', "Wrong sanitizer result 44");
+// forms
+is(s.sanitize("<form></form>", 0), '<html><head></head><body><form></form></body></html>', "Wrong sanitizer result 45");
+is(s.sanitize("<fieldset><legend></legend></fieldset>", 0), '<html><head></head><body><fieldset><legend></legend></fieldset></body></html>', "Wrong sanitizer result 46");
+is(s.sanitize("<input>", 0), '<html><head></head><body><input></body></html>', "Wrong sanitizer result 47");
+is(s.sanitize("<button>foo</button>", 0), '<html><head></head><body><button>foo</button></body></html>', "Wrong sanitizer result 48");
+is(s.sanitize("<select><optgroup><option>foo</option></optgroup></select></button>", 0), '<html><head></head><body><select><optgroup><option>foo</option></optgroup></select></body></html>', "Wrong sanitizer result 49");
+is(s.sanitize("<form></form>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 50");
+is(s.sanitize("<fieldset><legend></legend></fieldset>", u.SanitizerDropForms), '<html><head></head><body><fieldset><legend></legend></fieldset></body></html>', "Wrong sanitizer result 51");
+is(s.sanitize("<input>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 52");
+is(s.sanitize("<button>foo</button>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 53");
+is(s.sanitize("<select><optgroup><option>foo</option></optgroup></select></button>", u.SanitizerDropForms), '<html><head></head><body></body></html>', "Wrong sanitizer result 54");
+// doctype
+is(s.sanitize("<!DOCTYPE html>", 0), '<!DOCTYPE html>\n<html><head></head><body></body></html>', "Wrong sanitizer result 55");
+// title
+is(s.sanitize("<title></title>", 0), '<html><head><title></title></head><body></body></html>', "Wrong sanitizer result 56");
+// Drop media
+is(s.sanitize("<img>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 57");
+is(s.sanitize("<svg>foo</svg>", u.SanitizerDropMedia), '<html><head></head><body>foo</body></html>', "Wrong sanitizer result 58");
+is(s.sanitize("<video><source></video>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 59");
+is(s.sanitize("<audio><source></audio>", u.SanitizerDropMedia), '<html><head></head><body></body></html>', "Wrong sanitizer result 60");
+// disallow 'formaction' attributes
+is(s.sanitize("<input formaction='http://mochi.test/'>", 0), '<html><head></head><body><input></body></html>', "Wrong sanitizer result 61");
+// disallow 'ping' attributes
+is(s.sanitize("<a ping='http://mochi.test/'></a>", 0), "<html><head></head><body><a></a></body></html>", "Wrong sanitizer result 62");
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug650784.html b/dom/base/test/test_bug650784.html
new file mode 100644
index 0000000000..aacc342899
--- /dev/null
+++ b/dom/base/test/test_bug650784.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650776
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650776</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=650776">Mozilla Bug 650776</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650776 **/
+
+var c = SpecialPowers.Ci.nsIDocumentEncoder;
+var s = SpecialPowers.ParserUtils;
+
+is(s.convertToPlainText("foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 1");
+is(s.convertToPlainText("foo foo foo", c.OutputWrap | c.OutputLFLineBreak, 7), "foo foo\nfoo", "Wrong conversion result 2");
+is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 3");
+is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputNoScriptContent, 0), "barfoo", "Wrong conversion result 4");
+is(s.convertToPlainText("foo\u00A0bar", c.OutputPersistNBSP | c.OutputLFLineBreak, 0), "foo\u00A0bar", "Wrong conversion result 5");
+is(s.convertToPlainText("foo\u00A0bar", c.OutputLFLineBreak, 0), "foo bar", "Wrong conversion result 6");
+is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 7");
+// OutputNoFramesContent doesn't actually work, because the flag gets overridden in all cases.
+is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputNoFramesContent | c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 8");
+is(s.convertToPlainText("<i>foo</i> <b>bar</b>", c.OutputFormatted | c.OutputLFLineBreak, 0), "/foo/ *bar*\n", "Wrong conversion result 9");
+is(s.convertToPlainText("<p>foo</p> <p>bar</p>", c.OutputLFLineBreak, 0), "foo\n\nbar", "Wrong conversion result 10");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug656283.html b/dom/base/test/test_bug656283.html
new file mode 100644
index 0000000000..2b1c792017
--- /dev/null
+++ b/dom/base/test/test_bug656283.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=656283
+-->
+<head>
+ <title>Test for Bug 656283</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="test()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=656283">Mozilla Bug 656283</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 656283 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var ifr;
+function test() {
+ var d = document.implementation.createHTMLDocument("");
+ is(d.activeElement, d.body, "Active element should be body by default! (1)");
+
+
+ ifr = document.getElementById("ifr");
+ ifr.onload = test2;
+ ifr.srcdoc = "1";
+}
+
+var firstDoc;
+function test2() {
+ firstDoc = ifr.contentDocument;
+ is(firstDoc.activeElement, firstDoc.body,
+ "Active element should be body by default! (2)");
+ ifr.onload = test3;
+ ifr.srcdoc = "<input>";
+}
+
+function test3() {
+ ifr.contentDocument.getElementsByTagName("input")[0].focus();
+ is(firstDoc.activeElement, firstDoc.body,
+ "Active element should be body by default! (3)");
+ ifr.remove();
+ is(firstDoc.activeElement, firstDoc.body,
+ "Active element should be body by default! (4)");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+<iframe id="ifr"></irame>
+</body>
+</html>
diff --git a/dom/base/test/test_bug664916.html b/dom/base/test/test_bug664916.html
new file mode 100644
index 0000000000..7089ee5d81
--- /dev/null
+++ b/dom/base/test/test_bug664916.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=664916
+-->
+<head>
+ <title>Test for Bug 664916</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=664916">Mozilla Bug 664916</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+
+/** Test for Bug 664916 **/
+var div = document.createElement("div");
+var textNode = document.createTextNode("x")
+var tagNameGetter = div.__lookupGetter__("tagName");
+
+var tagName = "";
+try {
+ tagName = tagNameGetter.call(textNode);
+ ok(false, "Should throw when calling tagname getter on text node");
+} catch(e) {
+ ok(true, "Should throw when calling tagname getter on text node");
+}
+is(tagName, "", "Should not have changed tagName yet");
+tagName = tagNameGetter.call(div);
+is(tagName, "DIV", "Should get the right tag name");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug666604.html b/dom/base/test/test_bug666604.html
new file mode 100644
index 0000000000..1099db8a79
--- /dev/null
+++ b/dom/base/test/test_bug666604.html
@@ -0,0 +1,149 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666604
+-->
+<head>
+ <title>Test for Bug 666604</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=666604">Mozilla Bug 666604</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<a href="javascript:activationListener()" id="testlink">test</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 666604 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function hitEventLoop(times, next)
+{
+ if (times == 0) {
+ next();
+ return;
+ }
+
+ SimpleTest.executeSoon(function() {
+ hitEventLoop(times - 1, next);
+ });
+}
+
+var activationListener;
+
+function dispatchClick(target, ctrl) {
+ var e = document.createEvent("MouseEvent");
+ e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0,
+ ctrl, false, false, false, 0, null);
+ target.dispatchEvent(e);
+}
+
+function dispatchReturn(target, ctrl) {
+ var e = new KeyboardEvent("keypress", {
+ bubbles: true,
+ cancelable: true,
+ view: window,
+ ctrlKey: ctrl,
+ keyCode: 13,
+ charCode: 0,
+ });
+ target.dispatchEvent(e);
+}
+
+function dispatchDOMActivate(target) {
+ var e = document.createEvent("UIEvent");
+ e.initUIEvent("DOMActivate", true, true, window, 0);
+ target.dispatchEvent(e);
+}
+
+var testlink = document.getElementById("testlink");
+function test1() {
+ activationListener =
+ function() {
+ ok(true, "Untrusted click should activate a link");
+ test2();
+ }
+ dispatchClick(testlink, false);
+}
+
+function test2() {
+ activationListener =
+ function() {
+ ok(true, "Untrusted return keypress should activate a link");
+ test3();
+ }
+ dispatchReturn(testlink, false);
+}
+
+function test3() {
+ activationListener =
+ function() {
+ ok(false, "Untrusted click+ctrl should not activate a link");
+ test4();
+ }
+ dispatchClick(testlink, true);
+ hitEventLoop(10, test4);
+}
+
+function test4() {
+ activationListener =
+ function() {
+ ok(false, "Untrusted return keypress+ctrl should not activate a link");
+ test5();
+ }
+ dispatchReturn(testlink, true);
+ hitEventLoop(10, test5);
+}
+
+function test5() {
+ activationListener =
+ function() {
+ ok(true, "click() should activate a link");
+ test6();
+ }
+ testlink.click();
+}
+
+function test6() {
+ activationListener =
+ function() {
+ ok(true, "Untrusted DOMActivate should activate a link");
+ SpecialPowers.pushPrefEnv({"set":[["dom.disable_open_during_load", false]]}, test7);
+ }
+ dispatchDOMActivate(testlink);
+}
+
+function test7() {
+ testlink.href = "javascript:opener.activationListener(); window.close();";
+ testlink.target = "_blank";
+ testlink.rel = "opener";
+ activationListener =
+ function() {
+ ok(true, "Click() should activate a link");
+ SpecialPowers.pushPrefEnv({"set":[["dom.disable_open_during_load", true]]}, test8);
+ }
+ testlink.click();
+}
+
+function test8() {
+ testlink.href = "javascript:opener.activationListener(); window.close();";
+ testlink.target = "_blank";
+ testlink.rel = "opener";
+ activationListener =
+ function() {
+ ok(false, "Click() should not activate a link");
+ }
+ testlink.click();
+ SimpleTest.executeSoon(SimpleTest.finish);
+}
+addLoadEvent(test1);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug675121.html b/dom/base/test/test_bug675121.html
new file mode 100644
index 0000000000..d0d15b1f6e
--- /dev/null
+++ b/dom/base/test/test_bug675121.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=675121
+-->
+<head>
+ <title>Test for Bug 675121</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=675121">Mozilla Bug 675121</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 675121 **/
+var callbackFired = false;
+var xhrInProgress = false;
+function f() {
+ callbackFired = true;
+ if (!xhrInProgress) {
+ SimpleTest.finish();
+ }
+}
+
+window.requestAnimationFrame(f);
+var xhr = new XMLHttpRequest();
+xhr.open("GET", "file_bug675121.sjs", false);
+xhrInProgress = true;
+xhr.send();
+xhrInProgress = false;
+is(xhr.responseText, "Responded", "Should have a response by now");
+is(callbackFired, false, "Callback should not fire during sync XHR");
+
+if (!callbackFired) {
+ SimpleTest.waitForExplicitFinish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug675166.html b/dom/base/test/test_bug675166.html
new file mode 100644
index 0000000000..9543eb4e1f
--- /dev/null
+++ b/dom/base/test/test_bug675166.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=675166
+-->
+<head>
+ <title>Test for Bug 675166</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=675166">Mozilla Bug 675166</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 675166 **/
+
+
+var dt = document.implementation.createDocumentType("html", null, null);
+isnot(dt.ownerDocument, null, "DocumentType should have ownerDocument");
+
+var d = document.implementation.createDocument(null, null, dt);
+is(dt.ownerDocument, d, "DocumentType shouldn't have null ownerDocument");
+
+try {
+ document.implementation.createDocument(null, null, dt);
+ ok(true, "Creating document using already bound document type shouldn't throw!");
+} catch(ex) {
+ ok(false, "Creating document using already bound document type shouldn't throw!");
+}
+
+var d2 = document.implementation.createDocument(null, null, null);
+var dt2 = document.implementation.createDocumentType("html", null, null);
+d2.appendChild(dt2);
+is(dt2.ownerDocument, d2, "DocumentType shouldn't have null ownerDocument");
+
+is(document.ownerDocument, null, "Document's ownerDocument should be null!");
+is(document.documentElement.ownerDocument, document,
+ "Element should have ownerDocument!")
+
+is(dt2.parentNode, d2, "parentNode should be document!");
+d2.removeChild(dt2);
+is(dt2.parentNode, null, "parentNode should be null!");
+
+d.adoptNode(dt2);
+d2.adoptNode(dt2);
+d2.appendChild(dt2);
+is(dt2.parentNode, d2, "parentNode should be document!");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug682463.html b/dom/base/test/test_bug682463.html
new file mode 100644
index 0000000000..91b06b7407
--- /dev/null
+++ b/dom/base/test/test_bug682463.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=682463
+-->
+<head>
+ <title>Test for Bug 682463</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=682463">Mozilla Bug 682463</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 682463 **/
+
+ function text(s) {
+ return document.createTextNode(s);
+ }
+ function div(l,r) {
+ var d = document.createElement("DIV");
+ if (l) d.appendChild(l);
+ if (r) d.appendChild(r);
+ return d;
+ }
+ function createRange(sn,so,en,eo) {
+ var r = document.createRange();
+ r.setStart(sn,so);
+ r.setEnd(en,eo);
+ return r;
+ }
+ function verifyRange(msg,r,sn,so,en,eo) {
+ ok(r.startContainer == sn && r.startOffset == so &&
+ r.endContainer == en && r.endOffset == eo, msg);
+ }
+ function showRange(r,msg) {
+ var s = "" + r.startContainer + ": " + r.startOffset;
+ s+= '\n';
+ s += "" + r.endContainer + ": " + r.endOffset;
+ alert(msg + ':\n' + s)
+ }
+
+ var tests = [
+ function() {
+ var t = text("foobar");
+ var r = createRange(t,2,t,t.length);
+ var t2 = t.splitText(1);
+ verifyRange("split before, no parent",r,t2,1,t2,5);
+ },
+ function() {
+ var t = text("foobar");
+ var r = createRange(t,0,t,t.length);
+ var t2 = t.splitText(3);
+ verifyRange("split middle, no parent",r,t,0,t,3);
+ },
+ function() {
+ var t = text("foobar");
+ var r = createRange(t,0,t,t.length);
+ var n = t.length;
+ var t2 = t.splitText(n);
+ verifyRange("split after, no parent",r,t,0,t,n);
+ },
+ function() {
+ var t = text("foobar");
+ var parent = div(t);
+ var r = createRange(t,0,t,t.length);
+ var t2 = t.splitText(3);
+ verifyRange("split middle, parent",r,t,0,t2,3);
+ parent.removeChild(t);
+ verifyRange("removed left, parent",r,parent,0,t2,3);
+ var t2b = t2.splitText(1);
+ verifyRange("split middle, parent, end",r,parent,0,t2b,2);
+ },
+ function() {
+ var t0 = text("x");
+ var t = text("foobar");
+ var parent = div(t0,t);
+ var r = createRange(t,0,t,t.length);
+ var t2 = t.splitText(3);
+ parent.removeChild(t);
+ verifyRange("removed left, text sibling",r,parent,1,t2,3);
+ },
+ function() {
+ var t = text("foobar");
+ var parent = div(t);
+ var r = createRange(t,2,t,t.length);
+ var t2 = t.splitText(1);
+ verifyRange("split before, parent",r,t2,1,t2,5);
+ parent.removeChild(t2);
+ verifyRange("removed right, parent",r,parent,1,parent,1);
+ },
+ function() {
+ var t = text("foobar");
+ var parent = div(t);
+ var r = createRange(t,0,t,t.length);
+ var n = t.length;
+ var t2 = t.splitText(n);
+ verifyRange("split after, parent",r,t,0,t,n);
+ r.setEnd(t2,0);
+ verifyRange("split after, parent, extend",r,t,0,t2,0);
+ t2.splitText(0);
+ verifyRange("split after, parent, extend, split end",r,t,0,t2,0);
+ t2.textContent = "baz";
+ t2.splitText(2);
+ verifyRange("split after, parent, extend, split after end",r,t,0,t2,0);
+ r.setEnd(t2,2);
+ var t2b = t2.splitText(1);
+ verifyRange("split after, parent, split end",r,t,0,t2b,1);
+ },
+ function() {
+ var t = text("foobar");
+ var parent = div(t);
+ document.body.appendChild(parent);
+ var r = createRange(t,0,t,t.length);
+ var t2 = t.splitText(3);
+ verifyRange("split middle, in document",r,t,0,t2,3);
+ },
+ function() {
+ var t = text("foobar");
+ var parent = div(t);
+ document.body.appendChild(parent);
+ var r = createRange(t,2,t,t.length);
+ var t2 = t.splitText(1);
+ verifyRange("split before, in document",r,t2,1,t2,5);
+ },
+ function() {
+ var t = text("foobar");
+ var parent = div(t);
+ document.body.appendChild(parent);
+ var r = createRange(t,0,t,t.length);
+ var n = t.length;
+ var t2 = t.splitText(n);
+ verifyRange("split after, in document",r,t,0,t,n);
+ }
+ ];
+
+ function runTests() {
+ var len = tests.length;
+ for (var i = 0; i < len; ++i) {
+ tests[i]();
+ }
+ SimpleTest.finish();
+ }
+
+addLoadEvent(runTests);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug682554.html b/dom/base/test/test_bug682554.html
new file mode 100644
index 0000000000..4ad9e61e5e
--- /dev/null
+++ b/dom/base/test/test_bug682554.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=682554
+-->
+<head>
+ <title>Test for Bug 682554</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=682554">Mozilla Bug 682554</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 682554 **/
+is("onreadystatechange" in window, false,
+ "Window should not have an onreadystatechange");
+is("onreadystatechange" in document, true,
+ "Document should have an onreadystatechange");
+is("onreadystatechange" in document.createElement("script"), false,
+ "<script> element should not have an onreadystatechange");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug682592.html b/dom/base/test/test_bug682592.html
new file mode 100644
index 0000000000..c0271e2ee1
--- /dev/null
+++ b/dom/base/test/test_bug682592.html
@@ -0,0 +1,178 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=682592
+-->
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
+ <title>Test for bug 682592</title>
+ <script src="/tests/SimpleTest/WindowSnapshot.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">
+<iframe id="iframe-ref"></iframe>
+<iframe id="iframe-test"></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 682592 **/
+
+/*
+ We want to check that bidi is detected correctly. So, we have a reference
+ document where ltr is set explicitely with <bdo> element. Then, we compare
+ it with test document.
+
+ In mozilla, once bidi has been detected in a document, document always
+ consider it's in bidi mode. So, if one fragment enables bidi correctly, and
+ we create or update a fragment in the same document, that operation may not
+ enable bidi by itself, but it will not be detected. So, we need to have new
+ document for each test.
+
+ So, instead of many diferent reftests, this mochitest implements a
+ reftest-like. It creates reference text fragments in reference iframe, test
+ text fragments in test iframe, and compare the documents. Then, it reloads
+ test iframe. Reference iframe does not need to be reloaded between tests.
+ It's ok (and maybe, desired) to keep bidi always enabled in that document.
+*/
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestLongerTimeout(3);
+if (navigator.platform.startsWith("Linux arm")) { /* bugs 982875, 999429 */
+ SimpleTest.expectAssertions(0, 4);
+}
+
+var page = `<!DOCTYPE html>
+<html><meta charset='UTF-8'><body><p id="content"></p></body></html>`;
+var refFrame = document.getElementById("iframe-ref")
+var testFrame = document.getElementById("iframe-test");
+
+refFrame.addEventListener("load", function() {
+ testFrame.addEventListener("load", async function() {
+ let {done} = tests.next();
+ if (!done) {
+ ok(compareSnapshots(await snapshotWindow(testFrame.contentWindow),
+ await snapshotWindow(refFrame.contentWindow), true)[0],
+ "bidi is not detected correctly");
+
+ testFrame.contentWindow.location.reload();
+ } else {
+ SimpleTest.finish();
+ }
+ });
+ testFrame.srcdoc = page;
+});
+refFrame.srcdoc = page;
+
+var rtl = "עִבְרִית";
+var non8bit = "ʃ";
+var is8bit = "a";
+
+// concats aStr aNumber of times
+function strMult(aStr, aNumber) {
+ if (aNumber === 0) {
+ return "";
+ }
+ return strMult(aStr, aNumber - 1) + aStr;
+}
+
+function* runTests () {
+ var ltr = "", prefix = null;
+ var refContainer = refFrame.contentDocument.getElementById('content');
+ var testContainer, textNode;
+ var i = 0;
+
+ // 8bit chars + bidi
+ for (i = 0; i <= 16; i++) {
+ ltr = strMult(is8bit, i);
+ refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ testContainer.innerHTML = ltr + rtl;
+ yield undefined;
+ }
+
+ // non-8bit char + 8bit chars + bidi
+ for (i = 0; i <= 16; i++) {
+ ltr = non8bit + strMult(is8bit, i);
+ refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ testContainer.innerHTML = ltr + rtl;
+ yield undefined;
+ }
+
+ // appendData
+ for (i = 0; i <= 16; i++) {
+ ltr = strMult(is8bit, i);
+ refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ textNode = document.createTextNode("");
+ testContainer.appendChild(textNode);
+ textNode.appendData(ltr + rtl);
+ yield undefined;
+ }
+
+ for (i = 0; i <= 16; i++) {
+ ltr = non8bit + strMult(is8bit, i);
+ refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ textNode = document.createTextNode("");
+ testContainer.appendChild(textNode);
+ textNode.appendData(ltr + rtl);
+ yield undefined;
+ }
+
+ // appendData with 8bit prefix
+ for (i = 0; i <= 16; i++) {
+ prefix = is8bit;
+ ltr = strMult(is8bit, i);
+ refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ textNode = document.createTextNode(prefix);
+ testContainer.appendChild(textNode);
+ textNode.appendData(ltr + rtl);
+ yield undefined;
+ }
+
+ for (i = 0; i <= 16; i++) {
+ prefix = is8bit;
+ ltr = non8bit + strMult(is8bit, i);
+ refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ textNode = document.createTextNode(prefix);
+ testContainer.appendChild(textNode);
+ textNode.appendData(ltr + rtl);
+ yield undefined;
+ }
+
+ // appendData with non-8bit prefix
+ for (i = 0; i <= 16; i++) {
+ prefix = non8bit;
+ ltr = strMult(is8bit, i);
+ refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ textNode = document.createTextNode(prefix);
+ testContainer.appendChild(textNode);
+ textNode.appendData(ltr + rtl);
+ yield undefined;
+ }
+
+ for (i = 0; i <= 16; i++) {
+ prefix = non8bit;
+ ltr = non8bit + strMult(is8bit, i);
+ refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+ testContainer = testFrame.contentDocument.getElementById('content');
+ textNode = document.createTextNode(prefix);
+ testContainer.appendChild(textNode);
+ textNode.appendData(ltr + rtl);
+ yield undefined;
+ }
+};
+
+var tests = runTests();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug684671.html b/dom/base/test/test_bug684671.html
new file mode 100644
index 0000000000..996585d99d
--- /dev/null
+++ b/dom/base/test/test_bug684671.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=684671
+-->
+<head>
+ <title>Test for Bug 684671</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=684671">Mozilla Bug 684671</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 684671 **/
+function f() {}
+document.onreadystatechange = f;
+is(document.onreadystatechange, f,
+ "Document onreadystatechange should be settable");
+
+window.onreadystatechange = f;
+is(window.onreadystatechange, f,
+ "Window onreadystatechange should be settable");
+
+document.documentElement.onreadystatechange = f;
+is(document.documentElement.onreadystatechange, f,
+ "Element onreadystatechange should be settable");
+
+var canSetReadyStateChange;
+try {
+ XMLDocument.prototype.onreadystatechange = null;
+ canSetReadyStateChange = true;
+} catch (e) {
+ canSetReadyStateChange = false;
+}
+ok(canSetReadyStateChange, "This may break web pages");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug685798.html b/dom/base/test/test_bug685798.html
new file mode 100644
index 0000000000..25fb276ec1
--- /dev/null
+++ b/dom/base/test/test_bug685798.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=685798
+-->
+<head>
+ <title>Test for Bug 685798</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=685798">Mozilla Bug 685798</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 685798 **/
+
+
+is(document.parentElement, null,
+ "Document shouldn't have parentElement.");
+is(document.documentElement.parentElement, null,
+ "DocumentElement shouldn't have parentElement.");
+is(document.documentElement.firstChild.parentElement, document.documentElement,
+ "DocumentElement's child should have DocumentElement as parent.");
+
+var df = document.createRange().createContextualFragment("<div>foo</div>");
+is(df.parentElement, null,
+ "DocumentFragment should be null.");
+is(df.firstChild.parentElement, null,
+ "DocumentFragment's child shouldn't have parentElement");
+is(df.firstChild.firstChild.parentElement, df.firstChild,
+ "Text node's parent should be element.");
+
+is(document.createTextNode("foo").parentElement, null,
+ "Text node shouldn't have parent element.");
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug686449.xhtml b/dom/base/test/test_bug686449.xhtml
new file mode 100644
index 0000000000..4f639154da
--- /dev/null
+++ b/dom/base/test/test_bug686449.xhtml
@@ -0,0 +1,79 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=686449
+-->
+<head>
+ <title>Test for Bug 686449</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=686449">Mozilla Bug 686449</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="rangetest">abcd<div id="picontainer1"><?pi efgh?></div><div>ijkl</div><div id="picontainer2"><?pi mnop?></div>qrst</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 686449 **/
+
+var pi = document.createProcessingInstruction("t", "data");
+ok("target" in pi, "No target?");
+ok("data" in pi, "No data?");
+ok("length" in pi, "No length?");
+ok("substringData" in pi, "No substringData?");
+ok("appendData" in pi, "No appendData?");
+ok("insertData" in pi, "No insertData?");
+ok("deleteData" in pi, "No deleteData?");
+ok("replaceData" in pi, "No replaceData?");
+
+is(pi.substringData(0, pi.length), pi.data, "wrong data?");
+var olddata = pi.data;
+var appenddata = "foo"
+pi.appendData(appenddata);
+is(pi.data, olddata + appenddata, "appendData doesn't work?");
+pi.deleteData(olddata.length, appenddata.length);
+is(pi.data, olddata, "deleteData doesn't work?");
+pi.replaceData(0, 0, olddata);
+is(pi.data, olddata + olddata, "replaceData doesn't work?");
+pi.insertData(0, olddata);
+is(pi.data, olddata + olddata + olddata, "insertData doesn't work?");
+pi.data = olddata;
+is(pi.data, olddata, "setting data doesn't work?");
+
+var r = document.createRange();
+r.selectNodeContents(pi);
+is(r.startContainer, pi, "Wrong startContainer!");
+is(r.startOffset, 0, "Wrong startOffset!");
+is(r.endContainer, pi, "Wrong endContainer!");
+is(r.endOffset, pi.length, "Wrong endOffset!");
+
+var df = r.cloneContents();
+is(df.childNodes.length, 1, "Unexpected child nodes?");
+ok(df.firstChild.isEqualNode(pi), "Wrong cloning?");
+
+r.setStart(pi, 1);
+r.setEnd(pi, 3);
+df = r.cloneContents();
+is(df.childNodes.length, 1, "Unexpected child nodes?");
+ok(!df.firstChild.isEqualNode(pi), "Should clone to similar pi!");
+is(df.firstChild.data, "at", "Wrong data cloning?");
+
+r.selectNode(document.getElementById("rangetest"));
+is(r.toString(), document.getElementById("rangetest").textContent,
+ "Wrong range stringification!");
+ok(r.cloneContents().firstChild.firstChild.nextSibling.firstChild.
+ isEqualNode(document.getElementById("picontainer1").firstChild),
+ "Wrong pi cloning!");
+ok(r.cloneContents().firstChild.firstChild.nextSibling.nextSibling.nextSibling.firstChild.
+ isEqualNode(document.getElementById("picontainer2").firstChild),
+ "Wrong pi cloning!");
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug687859.html b/dom/base/test/test_bug687859.html
new file mode 100644
index 0000000000..455a14a9b2
--- /dev/null
+++ b/dom/base/test/test_bug687859.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=687859
+-->
+<head>
+ <meta charset="windows-1251">
+ <title>Test for Bug 687859</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=687859">Mozilla Bug 687859</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script charset="ISO-8859-2" src="file_bug687859-bom.js"></script>
+<script charset="ISO-8859-2" src="file_bug687859-16.js"></script>
+<script charset="ISO-8859-2" src="file_bug687859-http.js"></script>
+<script charset="ISO-8859-2" src="file_bug687859-charset.js"></script>
+<script src="file_bug687859-inherit.js"></script>
+<script type="application/javascript">
+is(stringFromBomScript, "\u20AC", "Bogus encoding for UTF-8 BOM case.");
+is(stringFrom16Script, "\u20AC", "Bogus encoding for UTF-16 BOM case.");
+is(stringFromHttpScript, "\u0E44", "Bogus encoding for HTTP case.");
+is(stringFromCharsetScript, "\u0104", "Bogus encoding for charset case.");
+is(stringFromInheritScript, "\u040E", "Bogus encoding for inherit case.");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug690056.html b/dom/base/test/test_bug690056.html
new file mode 100644
index 0000000000..cfe483bfe1
--- /dev/null
+++ b/dom/base/test/test_bug690056.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=690056
+-->
+<head>
+ <title>Test for Bug 690056</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=690056">Mozilla Bug 690056</a>
+<p id="display">
+ <iframe id="x"></iframe>
+ <iframe style="display: none" id="y"></iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 690056 **/
+SimpleTest.waitForExplicitFinish();
+is(document.hidden, false, "Document should not be hidden during load");
+is(document.visibilityState, "visible",
+ "Document should be visible during load");
+
+addLoadEvent(function() {
+ var doc = document.implementation.createDocument("", "", null);
+ is(doc.hidden, true, "Data documents should be hidden");
+ is(doc.visibilityState, "hidden", "Data documents really should be hidden");
+
+ is(document.hidden, false, "Document should not be hidden onload");
+ is(document.visibilityState, "visible",
+ "Document should be visible onload");
+
+ is($("x").contentDocument.hidden, false,
+ "Subframe document should not be hidden onload");
+ is($("x").contentDocument.visibilityState, "visible",
+ "Subframe document should be visible onload");
+ is($("y").contentDocument.hidden, false,
+ "display:none subframe document should not be hidden onload");
+ is($("y").contentDocument.visibilityState, "visible",
+ "display:none subframe document should be visible onload");
+
+ SimpleTest.finish();
+});
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug692434.html b/dom/base/test/test_bug692434.html
new file mode 100644
index 0000000000..eeb659ee3a
--- /dev/null
+++ b/dom/base/test/test_bug692434.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=692434
+-->
+<head>
+ <title>Test for Bug 692434</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 onload=runTest();>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=692434">Mozilla Bug 692434</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 692434 **/
+SimpleTest.waitForExplicitFinish();
+
+var xhr = new XMLHttpRequest();
+
+function runTest() {
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4) {
+ ok(this.responseXML, "Should have gotten responseXML");
+ is(this.responseXML.characterSet, "windows-1251", "Wrong character encoding");
+ is(this.responseXML.documentElement.firstChild.data, "\u042E", "Decoded using the wrong encoding.");
+ is(this.responseText.indexOf("\u042E"), 51, "Bad responseText");
+ SimpleTest.finish();
+ }
+ }
+ xhr.open("GET", "file_bug692434.xml");
+ xhr.send();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug693615.html b/dom/base/test/test_bug693615.html
new file mode 100644
index 0000000000..2be7311d5e
--- /dev/null
+++ b/dom/base/test/test_bug693615.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=693615
+-->
+<head>
+ <title>Test for Bug 693615</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=693615">Mozilla Bug 693615</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 693615 **/
+/*
+The following code tests if calling the DOM method Node::lookupNamespaceURI
+directly (with quickstubs) and through XPCOM leads to the same result.
+*/
+
+var content = document.getElementById("content");
+
+// called directly (quickstubs)
+var defaultNS = content.lookupNamespaceURI(null);
+is(defaultNS, null, "direct access working");
+
+// called via XPCOM
+// deleting the method from the prototype forces the engine to go through XPCOM
+var proto = Object.getPrototypeOf(content);
+delete(proto.lookupNamespaceURI);
+var wrapperNS = content.lookupNamespaceURI(null);
+is(wrapperNS, null, "access through XPCOM working");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug693875.html b/dom/base/test/test_bug693875.html
new file mode 100644
index 0000000000..33c6648e0d
--- /dev/null
+++ b/dom/base/test/test_bug693875.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=693875
+-->
+<head>
+ <title>Test for Bug 693875</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=693875">Mozilla Bug 693875</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 693875 **/
+
+var dp = new DOMParser();
+var d = dp.parseFromString("<?xml version='1.0'?><svg xmlns='http://www.w3.org/2000/svg'></svg>",
+ "image/svg+xml");
+
+ok(d instanceof XMLDocument, "Should have created an XML document.");
+ok("documentElement" in d, "Should have created an XML document, which has .documentElement.");
+is(d.documentElement.localName, "svg", "Root element should be svg.");
+is(d.documentElement.namespaceURI, "http://www.w3.org/2000/svg",
+ "Root element should be in svg namespace.");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug694754.xhtml b/dom/base/test/test_bug694754.xhtml
new file mode 100644
index 0000000000..a31c0a910c
--- /dev/null
+++ b/dom/base/test/test_bug694754.xhtml
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:test="http://example.com/test">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=694754
+-->
+<head>
+ <title>Test for Bug 694754</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=694754">Mozilla Bug 694754</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 694754 **/
+/*
+The following code tests if calling the DOM methods Document::lookupNamespaceURI
+and Document::lookupPrefix directly (with quickstubs) and through XPCOM leads
+to the same result.
+
+This test makes use of the bug/feature that deleting a method from the
+prototype forces the engine to go through XPCOM.
+*/
+
+// Document::lookupPrefix called directly (quickstubs)
+var prefixDirect = document.lookupPrefix("http://example.com/test");
+is(prefixDirect, "test",
+ "calling Document::lookupPrefix through quickstubs works");
+
+// Document::lookupPrefix called via XPCOM
+var proto = Object.getPrototypeOf(document);
+delete(proto.lookupPrefix);
+var prefixThroughXPCOM = document.lookupPrefix("http://example.com/test");
+is(prefixThroughXPCOM, "test",
+ "calling Document::lookupPrefix through XPCOM works");
+
+
+
+// Document::lookupNamespaceURI called directly (quickstubs)
+var namespaceDirect = document.lookupNamespaceURI(null);
+is(namespaceDirect, "http://www.w3.org/1999/xhtml",
+ "calling Document::lookupNamespaceURI through quickstubs works");
+
+// Document::lookupNamespaceURI called via XPCOM
+delete(proto.lookupNamespaceURI);
+var namespaceThroughXPCOM = document.lookupNamespaceURI(null);
+is(namespaceThroughXPCOM, "http://www.w3.org/1999/xhtml",
+ "calling Document::lookupNamespaceURI through XPCOM works");
+
+// Document::isDefaultNamespace called directly (quickstubs)
+var isDefaultNamespaceDirect = document.isDefaultNamespace("http://www.w3.org/1999/xhtml");
+is(isDefaultNamespaceDirect, true,
+ "Default namespace correctly detected through quickstubs");
+
+// Document::isDefaultNamespace called via XPCOM
+delete(proto.isDefaultNamespace);
+var isDefaultNamespaceXPCOM = document.isDefaultNamespace("http://www.w3.org/1999/xhtml");
+is(isDefaultNamespaceXPCOM, true,
+ "Default namespace correctly detected through XPCOM");
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug696301-1.html b/dom/base/test/test_bug696301-1.html
new file mode 100644
index 0000000000..b3202c85d6
--- /dev/null
+++ b/dom/base/test/test_bug696301-1.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=696301
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 696301</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=696301">Mozilla Bug 696301</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+var errorFired = false;
+var global = "";
+window.onerror = function(message, uri, line) {
+ is(message, "Script error.", "Should have empty error message");
+ is(uri,
+ "http://example.com/tests/dom/base/test/bug696301-script-1.js",
+ "Should have correct script URI");
+ is(line, 0, "Shouldn't have a line here");
+ errorFired = true;
+}
+</script>
+<script src="http://example.com/tests/dom/base/test/bug696301-script-1.js"></script>
+<script>
+ is(errorFired, true, "Should have error in different origin script");
+ is(global, "ran", "Different origin script should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.onerror = function(message, uri, line) {
+ is(message, "ReferenceError: c is not defined", "Should have correct error message");
+ is(uri,
+ "http://example.com/tests/dom/base/test/bug696301-script-1.js",
+ "Should also have correct script URI");
+ is(line, 3, "Should have a line here");
+ errorFired = true;
+}
+</script>
+<script src="http://example.com/tests/dom/base/test/bug696301-script-1.js"
+ crossorigin></script>
+<script>
+ is(errorFired, true, "Should have error in different origin script with CORS");
+ is(global, "ran", "Different origin script with CORS should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.addEventListener("error", function(e) {
+ is(Object.getPrototypeOf(e), Event.prototype,
+ "Object prototype should be Event");
+ var externalScripts = document.querySelectorAll("script[src]");
+ is(e.target, externalScripts[externalScripts.length - 1],
+ "Event's target should be the right <script>");
+ errorFired = true;
+}, true);
+</script>
+<script src="http://example.com/tests/dom/base/test/bug696301-script-2.js"
+ crossorigin></script>
+<script>
+ is(errorFired, true,
+ "Should have error when different origin script fails CORS check");
+ is(global, "", "Different origin script that fails CORS should not have run");
+</script>
+
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug696301-2.html b/dom/base/test/test_bug696301-2.html
new file mode 100644
index 0000000000..4204ae269d
--- /dev/null
+++ b/dom/base/test/test_bug696301-2.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=696301
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 696301</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=696301">Mozilla Bug 696301</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<!-- Test SVG script here -->
+<svg>
+<script type="application/javascript">
+var errorFired = false;
+var global = "";
+window.onerror = function(message, uri, line) {
+ is(message, "Script error.", "Should have empty error message");
+ is(uri,
+ "http://example.com/tests/dom/base/test/bug696301-script-1.js",
+ "Should have correct script URI");
+ is(line, 0, "Shouldn't have a line here");
+ errorFired = true;
+}
+</script>
+<script xlink:href="http://example.com/tests/dom/base/test/bug696301-script-1.js"></script>
+<script>
+ is(errorFired, true, "Should have error in different origin script");
+ is(global, "ran", "Different origin script should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.onerror = function(message, uri, line) {
+ is(message, "ReferenceError: c is not defined", "Should have correct error message");
+ is(uri,
+ "http://example.com/tests/dom/base/test/bug696301-script-1.js",
+ "Should also have correct script URI");
+ is(line, 3, "Should have a line here");
+ errorFired = true;
+}
+</script>
+<script xlink:href="http://example.com/tests/dom/base/test/bug696301-script-1.js"
+ crossorigin></script>
+<script>
+ is(errorFired, true, "Should have error in different origin script with CORS");
+ is(global, "ran", "Different origin script with CORS should have run");
+</script>
+
+<script type="application/javascript">
+errorFired = false;
+global = "";
+window.addEventListener("error", function(e) {
+ is(Object.getPrototypeOf(e), Event.prototype,
+ "Object prototype should be Event");
+ var scripts = document.querySelectorAll("script");
+ is(e.target, scripts[scripts.length - 1],
+ "Event's target should be the right &lt;script>");
+ errorFired = true;
+}, true);
+</script>
+<script xlink:href="http://example.com/tests/dom/base/test/bug696301-script-2.js"
+ crossorigin></script>
+<script>
+ is(errorFired, true,
+ "Should have error when different origin script fails CORS check");
+ is(global, "", "Different origin script that fails CORS should not have run");
+</script>
+</svg>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug698381.html b/dom/base/test/test_bug698381.html
new file mode 100644
index 0000000000..6fe84a1da2
--- /dev/null
+++ b/dom/base/test/test_bug698381.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=698381
+ -->
+ <head>
+ <title>Test for Bug 698381</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"
+ type="text/javascript"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+ </head>
+ <body onload="runTests();">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=698381">
+ Mozilla Bug 698381</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <div id="noChildren" style="display: none"></div>
+ <div id="hasChildren" style="display: none">
+ <div id="childOne" style="display: none"></div>
+ </div>
+ <pre id="test">
+ <script type="text/javascript">
+ /*
+ Checks to see if default parameter handling is correct when 0
+ parameters are passed.
+
+ If none are passed, then Node.cloneNode should default aDeep
+ to true.
+ */
+ SimpleTest.waitForExplicitFinish();
+
+ var hasChildren = document.getElementById("hasChildren"),
+ noChildren = document.getElementById("noChildren"),
+ clonedNode;
+
+ function runTests() {
+
+ // Test Node.cloneNode when no arguments are given
+ clonedNode = hasChildren.cloneNode();
+ is(clonedNode.hasChildNodes(), false, "Node.cloneNode with false " +
+ "default on a node with children does not clone the child nodes.");
+
+ clonedNode = noChildren.cloneNode();
+ is(clonedNode.hasChildNodes(), false, "Node.cloneNode with false " +
+ "default on a node without children doesn't clone child nodes." );
+
+ SimpleTest.finish();
+ }
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/base/test/test_bug698384.html b/dom/base/test/test_bug698384.html
new file mode 100644
index 0000000000..c2c4663b35
--- /dev/null
+++ b/dom/base/test/test_bug698384.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=698384
+ -->
+ <head>
+ <title>Test for Bug 698384</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"
+ type="text/javascript"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+ </head>
+ <body onload="runTests();">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=698384">
+ Mozilla Bug 698384</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ <script type="text/javascript">
+ /*
+ Checks to see if default parameter handling is correct when 0, 1
+ or 2 parameters are passed.
+
+ If one is only passed, aFilter should default to null
+ If none are passed, aFilter should be null and aWhatToShow should
+ be NodeFilter.SHOW_ALL
+ */
+ SimpleTest.waitForExplicitFinish();
+
+ var content = $('content'),
+ ni;
+
+ content.innerHTML = ('<span id="A"><\/span><span id="B"><\/span>'
+ + '<span id="C"><\/span>');
+
+ function runTests() {
+
+ // Test NodeIterator when no optional arguments are given
+ ni = document.createNodeIterator(content);
+ is(ni.whatToShow, NodeFilter.SHOW_ALL, "whatToShow should be " +
+ "NodeFilter.SHOW_ALL when both " +
+ " optionals are not given");
+ is(ni.filter, null, "filter should be defaulted to null when both " +
+ " optionals are not given");
+
+ // Test NodeIterator when first optional is passed
+ ni = document.createNodeIterator(content, NodeFilter.SHOW_ELEMENT);
+ is(ni.filter, null, "filter should be defaulted to null when only " +
+ " first argument is passed");
+ is(ni.whatToShow, NodeFilter.SHOW_ELEMENT, "whatToShow should " +
+ "properly be set to NodeFilter.SHOW_ELEMENT when whatToShow is " +
+ "provided and filter is not");
+
+ SimpleTest.finish();
+ }
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/base/test/test_bug704063.html b/dom/base/test/test_bug704063.html
new file mode 100644
index 0000000000..13d26d0a38
--- /dev/null
+++ b/dom/base/test/test_bug704063.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug </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 **/
+ SimpleTest.waitForExplicitFinish();
+ var firstRan = false;
+ var secondRan = false;
+ function second(time) {
+ is(firstRan, true, "We were called second");
+ secondRan = true;
+ ok(Math.abs(time - performance.now()) < 3600000,
+ "An hour really shouldn't have passed here");
+ ok(Math.abs(time - Date.now()) > 3600000,
+ "More than an hour should have passed since 1970");
+ }
+ function first(time) {
+ is(secondRan, false, "second() was called first");
+ firstRan = true;
+ ok(Math.abs(time - performance.now()) < 3600000,
+ "An hour really shouldn't have passed here either");
+ ok(Math.abs(time - Date.now()) > 3600000,
+ "More than an hour should have passed since 1970 here either");
+ }
+ function third() {
+ ok(firstRan, "We should be after the first call");
+ ok(secondRan, "We should be after the second call");
+ SimpleTest.finish();
+ }
+
+ window.onload = function() {
+ window.requestAnimationFrame(first);
+ window.requestAnimationFrame(second);
+ window.requestAnimationFrame(third);
+ }
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug704320-1.html b/dom/base/test/test_bug704320-1.html
new file mode 100644
index 0000000000..d20e6c0e1d
--- /dev/null
+++ b/dom/base/test/test_bug704320-1.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+This Test is split into two for Bug 1453396
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 704320-Part1</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="referrerHelper.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+//generates URLs to test
+var generateURLArray = (function(from, to){
+ const baseURL = '://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=';
+ const schemeTo = '&scheme-to=';
+
+ return [
+ from + baseURL + from + schemeTo + to + '&policy=no-referrer-when-downgrade',
+ from + baseURL + from + schemeTo + to + '&policy=no-referrer',
+ from + baseURL + from + schemeTo + to + '&policy=unsafe-url',
+ from + baseURL + from + schemeTo + to + '&policy=origin',
+ from + baseURL + from + schemeTo + to + '&policy=origin-when-cross-origin',
+ from + baseURL + from + schemeTo + to + '&policy=same-origin',
+ from + baseURL + from + schemeTo + to + '&policy=strict-origin',
+ from + baseURL + from + schemeTo + to + '&policy=strict-origin-when-cross-origin',
+ ];
+});
+
+let testIframeUrls = [generateURLArray('http', 'http'),
+ generateURLArray('https', 'https')];
+
+SimpleTest.waitForExplicitFinish();
+let advance = function(testName) {
+ testsGenerator[testName].next();
+};
+
+let testNames = ['testframeone', 'testframetwo'];
+let isTestFinished = 0;
+
+function checkTestsCompleted() {
+ isTestFinished++;
+ if (isTestFinished == 2) {
+ SimpleTest.finish();
+ }
+}
+let testsGenerator = {};
+SimpleTest.requestLongerTimeout(4);
+/**
+ * This is the main test routine -- serialized by use of a generator.
+ * It performs all tests in sequence using four iframes.
+ */
+function startTests(testName, iframeUrls) {
+ testsGenerator[testName] = (function*() {
+ var testframe = document.getElementById(testName);
+ testframe.onload = function() {
+ advance(testName);
+ }
+
+ // load the test frame from iframeUrls[url]
+ // it will call back into this function via postMessage when it finishes
+ // loading and continue beyond the yield.
+ for(url in iframeUrls) {
+ yield testframe.src = iframeUrls[url];
+ // run test and check result for loaded test URL
+ yield checkExpectedGlobalResults(testName);
+ }
+ checkTestsCompleted();
+ })();
+}
+
+for (i = 0; i < testIframeUrls.length; i++) {
+ startTests(testNames[i], testIframeUrls[i]);
+}
+
+</script>
+</head>
+
+<body onload="testsGenerator[testNames[0]].next();
+ testsGenerator[testNames[1]].next();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP/HTTPS to HTTPS/HTTP</a>
+<p id="display"></p>
+<pre id="content">
+</pre>
+ <iframe id="testframeone"></iframe>
+ <iframe id="testframetwo"></iframe>
+</body>
diff --git a/dom/base/test/test_bug704320-2.html b/dom/base/test/test_bug704320-2.html
new file mode 100644
index 0000000000..3c02e1d8d7
--- /dev/null
+++ b/dom/base/test/test_bug704320-2.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+This Test is split into two for Bug 1453396
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 704320-Part2</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="referrerHelper.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+//generates URLs to test
+var generateURLArray = (function(from, to){
+ const baseURL = '://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=';
+ const schemeTo = '&scheme-to=';
+
+ return [
+ from + baseURL + from + schemeTo + to + '&policy=no-referrer-when-downgrade',
+ from + baseURL + from + schemeTo + to + '&policy=no-referrer',
+ from + baseURL + from + schemeTo + to + '&policy=unsafe-url',
+ from + baseURL + from + schemeTo + to + '&policy=origin',
+ from + baseURL + from + schemeTo + to + '&policy=origin-when-cross-origin',
+ from + baseURL + from + schemeTo + to + '&policy=same-origin',
+ from + baseURL + from + schemeTo + to + '&policy=strict-origin',
+ from + baseURL + from + schemeTo + to + '&policy=strict-origin-when-cross-origin',
+ ];
+});
+
+let testIframeUrls = [generateURLArray('http', 'https'),
+ generateURLArray('https', 'http')];
+
+SimpleTest.waitForExplicitFinish();
+let advance = function(testName) {
+ testsGenerator[testName].next();
+};
+
+let testNames = ['testframeone', 'testframetwo'];
+let isTestFinished = 0;
+
+function checkTestsCompleted() {
+ isTestFinished++;
+ if (isTestFinished == 2) {
+ SimpleTest.finish();
+ }
+}
+let testsGenerator = {};
+SimpleTest.requestLongerTimeout(4);
+/**
+ * This is the main test routine -- serialized by use of a generator.
+ * It performs all tests in sequence using four iframes.
+ */
+function startTests(testName, iframeUrls) {
+ testsGenerator[testName] = (function*() {
+ var testframe = document.getElementById(testName);
+ testframe.onload = function() {
+ advance(testName);
+ }
+
+ // load the test frame from iframeUrls[url]
+ // it will call back into this function via postMessage when it finishes
+ // loading and continue beyond the yield.
+ for(url in iframeUrls) {
+ yield testframe.src = iframeUrls[url];
+ // run test and check result for loaded test URL
+ yield checkExpectedGlobalResults(testName);
+ }
+ checkTestsCompleted();
+ })();
+}
+
+for (i = 0; i < testIframeUrls.length; i++) {
+ startTests(testNames[i], testIframeUrls[i]);
+}
+
+</script>
+</head>
+
+<body onload="testsGenerator[testNames[0]].next();
+ testsGenerator[testNames[1]].next();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP/HTTPS to HTTPS/HTTP</a>
+<p id="display"></p>
+<pre id="content">
+</pre>
+ <iframe id="testframeone"></iframe>
+ <iframe id="testframetwo"></iframe>
+</body>
diff --git a/dom/base/test/test_bug704320_policyset.html b/dom/base/test/test_bug704320_policyset.html
new file mode 100644
index 0000000000..227c3b20a5
--- /dev/null
+++ b/dom/base/test/test_bug704320_policyset.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This checks if the right policies are applied from a given string (including whitespace, invalid policy strings, etc). It doesn't do a complete check for all load types; that's done in another test.
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+-->
+
+<head>
+ <meta charset="utf-8">
+ <title>Test policies for Bug 704320</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="referrerHelper.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * This is the main test routine -- serialized by use of a generator.
+ * It resets the counter, then performs two tests in sequence using
+ * the same iframe.
+ */
+var tests = (function*() {
+ var iframe = document.getElementById("testframe");
+ const sjs = "/tests/dom/base/test/bug704320.sjs?action=generate-policy-test";
+
+
+ // basic calibration check
+ // reset the counter
+ yield resetCounter();
+
+ // load the first test frame
+ // it will call back into this function via postMessage when it finishes loading.
+ // and continue beyond the yield.
+ yield iframe.src = sjs + "&policy=" + escape('default');
+
+ // check the first test (two images, no referrers)
+ yield checkIndividualResults("default", ["full"]);
+
+ // check invalid policy
+ // According to the spec section Determine token's Policy,if there is a policy
+ // token and it is not one of the expected tokens, Empty string should be the
+ // policy used.
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape('invalid-policy');
+ yield checkIndividualResults("invalid", ["full"]);
+
+ // whitespace checks.
+ // according to the spec section 4.1, the content attribute's value
+ // is fed to the token policy algorithm after stripping leading and
+ // trailing whitespace.
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape('default ');
+ yield checkIndividualResults("trailing whitespace", ["full"]);
+
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape(' origin\f');
+ yield checkIndividualResults("trailing form feed", ["origin"]);
+
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape('\f origin');
+ yield checkIndividualResults("leading form feed", ["origin"]);
+
+ // origin when cross-origin (trimming whitespace)
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape(' origin-when-cross-origin');
+ yield checkIndividualResults("origin-when-cross-origin", ["origin", "full"]);
+
+ // according to the spec section 4.1:
+ // "If the meta element lacks a content attribute, or if that attribute’s
+ // value is the empty string, then abort these steps."
+ // This means empty or missing content attribute means to ignore the meta
+ // tag and use default policy.
+ // Whitespace here is space, tab, LF, FF and CR.
+ // http://www.w3.org/html/wg/drafts/html/CR/infrastructure.html#space-character
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape(' \t ');
+ yield checkIndividualResults("basic whitespace only policy", ["full"]);
+
+ // and double-check that no-referrer works.
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape('no-referrer');
+ yield checkIndividualResults("no-referrer", ["none"]);
+
+ // Case insensitive
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape('\f OrigIn');
+ yield checkIndividualResults("origin case insensitive", ["origin"]);
+
+ // complete.
+ SimpleTest.finish();
+})();
+
+</script>
+</head>
+
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug704320_policyset2.html b/dom/base/test/test_bug704320_policyset2.html
new file mode 100644
index 0000000000..546107d594
--- /dev/null
+++ b/dom/base/test/test_bug704320_policyset2.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This checks if the right policies are applied from a given string (including whitespace, invalid policy strings, etc). It doesn't do a complete check for all load types; that's done in another test.
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+-->
+
+<head>
+ <meta charset="utf-8">
+ <title>Test policies for Bug 704320</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="referrerHelper.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * This is the main test routine -- serialized by use of a generator.
+ * It resets the counter, then performs two tests in sequence using
+ * the same iframe.
+ */
+var tests = (function*() {
+ var iframe = document.getElementById("testframe");
+ const sjs = "/tests/dom/base/test/bug704320.sjs?action=generate-policy-test";
+
+ yield resetCounter();
+ yield iframe.src = sjs + "&policy=" + escape(' \f\r\n\t ');
+ yield checkIndividualResults("whitespace only policy", ["full"]);
+
+ // complete.
+ SimpleTest.finish();
+})();
+
+</script>
+</head>
+
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug704320_preload.html b/dom/base/test/test_bug704320_preload.html
new file mode 100644
index 0000000000..b4ae415278
--- /dev/null
+++ b/dom/base/test/test_bug704320_preload.html
@@ -0,0 +1,136 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This is a spot check for whether the speculative parser reuses style, script or image loads after the referrer policy has changed.
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+-->
+
+<head>
+ <meta charset="utf-8">
+ <title>Test preloads for Bug 704320</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="referrerHelper.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * This is the main test routine -- serialized by use of a generator.
+ * It resets the counter, then performs two tests in sequence using
+ * the same iframe.
+ */
+var tests = (function*() {
+ var iframe = document.getElementById("testframe");
+
+ // reset the counter
+ yield resetCounter();
+
+ // load the second test frame
+ // it will call back into this function via postMessage when it finishes loading.
+ // and continue beyond the yield.
+ yield iframe.src = 'file_bug704320_preload_reuse.html';
+
+ // check the second test
+ yield checkResults(finalizePreloadReuse);
+
+ // reset the counter
+ yield resetCounter();
+
+ // load the third test frame
+ // it will call back into this function via postMessage when it finishes loading.
+ // and continue beyond the yield.
+ yield iframe.src = 'file_bug704320_preload_attr.html';
+
+ // check the third test
+ yield checkResults(finalizePreloadReferrerPolicyAttr);
+
+ // complete.
+ SimpleTest.finish();
+})();
+
+// Helper functions below.
+
+/**
+ * This checks the second test: a test where preloads SHOULD be reused.
+ * We expect one request for each image, script, js request since
+ * the referrer policy does not change after speculative loads.
+ */
+function finalizePreloadReuse(results) {
+ var expected = {'css': {'count': 1, 'referrers': ['origin']},
+ 'img': {'count': 1, 'referrers': ['origin']},
+ 'js': {'count': 1, 'referrers': ['origin']}};
+
+ for (var x in expected) {
+ ok(x in results, "some " + x + " loads required in results object.");
+
+ is(results[x].count, expected[x].count,
+ "Expected " + expected[x].count + " loads for " + x + " requests.");
+
+ // 'origin' is required
+ ok(results[x].referrers.includes('origin'),
+ "One load for " + x + " should have had 'origin' referrer.");
+
+ // no other values should be in the referrers.
+ is(results[x].referrers.indexOf('none'), -1,
+ "No loads for " + x + " should have a missing referrer.");
+ is(results[x].referrers.indexOf('full'), -1,
+ "No loads for " + x + " should have an 'full' referrer.")
+ }
+
+ advance();
+}
+
+/**
+ * This checks the third test: a test where preload requests of image, style
+ * should use referrerpolicy attribute and we expect the preloads should not
+ * be reused
+ */
+function finalizePreloadReferrerPolicyAttr(results) {
+ var expected = {'css': {'count': 1, 'referrers': ['origin']},
+ 'img': {'count': 1, 'referrers': ['origin']},
+ 'js': {'count': 1, 'referrers': ['origin']}};
+
+ for (var x in expected) {
+ ok(x in results, "some " + x + " loads required in results object.");
+
+ is(results[x].count, expected[x].count,
+ "Expected " + expected[x].count + " loads for " + x + " requests.");
+
+ // 'origin' is required
+ ok(results[x].referrers.includes('origin'),
+ "One load for " + x + " should have had 'origin' referrer.");
+
+ // no other values should be in the referrers.
+ is(results[x].referrers.indexOf('none'), -1,
+ "No loads for " + x + " should have a missing referrer.");
+ is(results[x].referrers.indexOf('full'), -1,
+ "No loads for " + x + " should have an 'full' referrer.")
+ }
+
+ advance();
+}
+
+/**
+ * Grabs the results via XHR and passes to checker.
+ */
+function checkResults(checker) {
+ doXHR('/tests/dom/base/test/bug704320_counter.sjs?results',
+ function(xhr) {
+ checker(JSON.parse(xhr.responseText));
+ },
+ function(xhr) {
+ ok(false, "Can't get results from the counter server.");
+ });
+}
+
+</script>
+</head>
+
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+
+</body>
+</html>
diff --git a/dom/base/test/test_bug707142.html b/dom/base/test/test_bug707142.html
new file mode 100644
index 0000000000..5326c1b96b
--- /dev/null
+++ b/dom/base/test/test_bug707142.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=707142
+-->
+<head>
+ <title>Test for Bug 707142</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=707142">Mozilla Bug 707142</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 707142 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var xhr = new XMLHttpRequest();
+xhr.onload = function() {
+ is(xhr.response.foo, "bar", "Should have gotten bar on baseline");
+
+ xhr.onload = function() {
+ is(xhr.response.foo, "bar", "Should have gotten bar with BOM");
+
+ xhr.onload = function() {
+ is(xhr.response, null, "Should have gotten null response with UTF-16 JSON");
+
+ SimpleTest.finish();
+ };
+ xhr.open("GET", "file_bug707142_utf-16.json");
+ xhr.responseType = "json";
+ xhr.send();
+ };
+ xhr.open("GET", "file_bug707142_bom.json");
+ xhr.responseType = "json";
+ xhr.send();
+};
+xhr.open("GET", "file_bug707142_baseline.json");
+xhr.responseType = "json";
+xhr.send();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug708620.html b/dom/base/test/test_bug708620.html
new file mode 100644
index 0000000000..d6b5b0c6d8
--- /dev/null
+++ b/dom/base/test/test_bug708620.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=708620
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 708620</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=708620"
+ >Mozilla Bug 708620</a>
+<iframe></iframe>
+<script>
+/** Test for Bug 708620 **/
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.monitorConsole(SimpleTest.finish, [
+ { errorMessage: "A form was submitted in the windows-1252 encoding "+
+ "which cannot encode all Unicode characters, so user "+
+ "input may get corrupted. To avoid this problem, the "+
+ "page should be changed so that the form is submitted "+
+ "in the UTF-8 encoding either by changing the encoding "+
+ "of the page itself to UTF-8 or by specifying "+
+ "accept-charset=utf-8 on the form element.",
+ isWarning: true }
+]);
+
+window.onload = function () {
+ document.getElementsByTagName("iframe")[0].src = "file_bug708620.html";
+}
+
+function finish() {
+ SimpleTest.endMonitorConsole();
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug711047.html b/dom/base/test/test_bug711047.html
new file mode 100644
index 0000000000..2aa8de3060
--- /dev/null
+++ b/dom/base/test/test_bug711047.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=711047
+-->
+<title>Test for Bug 711047</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=711047">Mozilla Bug 711047</a>
+<div id="content">
+</div>
+<pre id="test">
+<script>
+/** Test for Bug 711047 **/
+ok(!("RangeException" in window), "RangeException shouldn't exist");
+</script>
+</pre>
diff --git a/dom/base/test/test_bug711180.html b/dom/base/test/test_bug711180.html
new file mode 100644
index 0000000000..d80bc1b85b
--- /dev/null
+++ b/dom/base/test/test_bug711180.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=711180
+-->
+<head>
+ <title>Test for Bug 711180</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=711180">Mozilla Bug 711180</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 711180 **/
+is(atob("aQ=="), atob("\t a\rQ\n=\f="), "Base64 space removal");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug719533.html b/dom/base/test/test_bug719533.html
new file mode 100644
index 0000000000..4154b3bdb2
--- /dev/null
+++ b/dom/base/test/test_bug719533.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=719544
+-->
+<title>Test for Bug 719544</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=719544">Mozilla Bug 719544</a>
+<script>
+
+/** Test for Bug 719544 **/
+var threw = false;
+var origLength = document.childNodes.length;
+try {
+ var range = document.createRange();
+ range.selectNodeContents(document);
+ range.extractContents();
+} catch(e) {
+ threw = true;
+ is(Object.getPrototypeOf(e), DOMException.prototype,
+ "Must throw DOMException");
+ is(e.name, "HierarchyRequestError", "Must throw HierarchyRequestError");
+}
+ok(threw, "Must throw");
+is(document.childNodes.length, origLength, "Must preserve original children");
+
+</script>
diff --git a/dom/base/test/test_bug726364.html b/dom/base/test/test_bug726364.html
new file mode 100644
index 0000000000..29830a39f7
--- /dev/null
+++ b/dom/base/test/test_bug726364.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=726364
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 726364</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=726364">Mozilla Bug 726364</a>
+<p id="display"><div id="v">ABC</div></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 726364 **/
+function boom()
+{
+ var v = document.getElementById("v");
+ var t = v.firstChild;
+ is(v.childNodes.length,1, "child count");
+
+ var f = function(event) {
+ window.removeEventListener("DOMCharacterDataModified", f, true);
+ is(v.childNodes[0],t, "first child is the same");
+ is(v.childNodes.length,2, "child count");
+ r.setEnd(v, 0);
+ SimpleTest.finish();
+ };
+ window.addEventListener("DOMCharacterDataModified", f, true);
+
+ var r = document.createRange();
+ r.setStart(t, 2);
+ t.splitText(1);
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(boom);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug737087.html b/dom/base/test/test_bug737087.html
new file mode 100644
index 0000000000..008ad3bc03
--- /dev/null
+++ b/dom/base/test/test_bug737087.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=737087
+-->
+<title>Test for Bug 737087</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=737087">Mozilla Bug 737087</a>
+<script>
+
+/** Test for Bug 737087 **/
+SimpleTest.waitForExplicitFinish();
+
+var bubbled = false;
+var capturedEvent = null;
+var inlineFiredEvent = null;
+
+addEventListener("error", function() { bubbled = true });
+addEventListener("error", function(e) {
+ capturedEvent = e;
+ is(typeof e, "object", "Error event must be object");
+ is(Object.getPrototypeOf(e), Event.prototype, "Error event must be Event");
+ is(e.bubbles, false, "e.bubbles must be false");
+ is(e.cancelable, false, "e.cancelable must be false");
+}, true);
+
+addLoadEvent(function() {
+ is(bubbled, false, "Error event must not bubble");
+ isnot(capturedEvent, null, "Error event must be captured");
+ isnot(inlineFiredEvent, null, "Inline error handler must fire");
+ is(capturedEvent, inlineFiredEvent,
+ "Same event must be handled by both handlers");
+ SimpleTest.finish();
+});
+</script>
+<script src=nonexistent
+ onerror="inlineFiredEvent = event"></script>
diff --git a/dom/base/test/test_bug737565.html b/dom/base/test/test_bug737565.html
new file mode 100644
index 0000000000..9a24a70b9d
--- /dev/null
+++ b/dom/base/test/test_bug737565.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=737565
+-->
+<title>Test for Bug 737565</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=737565">Mozilla Bug 737565</a>
+<script>
+
+/** Test for Bug 737565 **/
+var offsets = [-1, 0, 1, 2, 3, 65536, 1 << 31];
+// This is supposed to be an unsigned long, so adding or subtracting 1 << 32
+// should have no effect
+var offsetOffsets = [0, -Math.pow(2, 32), Math.pow(2, 32)];
+
+for (var i = 0; i < offsets.length; i++) {
+ for (var j = 0; j < offsetOffsets.length; j++) {
+ var offset = offsets[i] + offsetOffsets[j];
+
+ // Doctype always needs to throw
+ var threw = false;
+ try {
+ var range = document.createRange();
+ range.comparePoint(document.doctype, offset);
+ } catch(e) {
+ threw = true;
+ is(e.name, "InvalidNodeTypeError",
+ "comparePoint(document.doctype, " + offset
+ + ") must throw InvalidNodeTypeError");
+ is(Object.getPrototypeOf(e), DOMException.prototype,
+ "comparePoint(document.doctype, " + offset
+ + ") must throw DOMException");
+ is(e.code, DOMException.INVALID_NODE_TYPE_ERR,
+ "comparePoint(document.doctype, " + offset
+ + ") must throw INVALID_NODE_TYPE_ERR");
+ }
+ ok(threw, "comparePoint(document.doctype, " + offset + ") must throw");
+
+ threw = false;
+ // document.documentElement has two children, head and body
+ var expectedThrew = offsets[i] < 0 || offsets[i] > 2;
+ try {
+ var range = document.createRange();
+ range.comparePoint(document.documentElement, offset);
+ } catch(e) {
+ threw = true;
+ is(e.name, "IndexSizeError",
+ "comparePoint(document.documentElement, " + offset
+ + ") must throw IndexSizeError");
+ is(Object.getPrototypeOf(e), DOMException.prototype,
+ "comparePoint(document.documentElement, " + offset
+ + ") must throw DOMException");
+ is(e.code, DOMException.INDEX_SIZE_ERR,
+ "comparePoint(document.documentElement, " + offset
+ + ") must throw INDEX_SIZE_ERR");
+ }
+ is(threw, expectedThrew,
+ "comparePoint(document.documentElement, " + offset
+ + ") must " + (expectedThrew ? "" : "not ") + "throw");
+ }
+}
+
+</script>
diff --git a/dom/base/test/test_bug737612.html b/dom/base/test/test_bug737612.html
new file mode 100644
index 0000000000..9a17ab06e6
--- /dev/null
+++ b/dom/base/test/test_bug737612.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=737612
+-->
+<title>Test for Bug 737612</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=737612">Mozilla Bug 737612</a>
+<script>
+
+/** Test for Bug 737612 **/
+var text = document.createTextNode("abc");
+var range = document.createRange();
+range.setStart(text, 1);
+var threw = false;
+try {
+ range.insertNode(document.head);
+} catch(e) {
+ var threw = true;
+ is(e.name, "HierarchyRequestError",
+ "Must throw HierarchyRequestError");
+ is(Object.getPrototypeOf(e), DOMException.prototype,
+ "Must throw DOMException");
+ is(e.code, DOMException.HIERARCHY_REQUEST_ERR,
+ "Must throw HIERARCHY_REQUEST_ERR");
+}
+ok(threw, "Must throw when insertNode()ing into detached text node");
+
+</script>
diff --git a/dom/base/test/test_bug738108.html b/dom/base/test/test_bug738108.html
new file mode 100644
index 0000000000..1ec69d83b9
--- /dev/null
+++ b/dom/base/test/test_bug738108.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=738108
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 738108</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=738108">Mozilla Bug 738108</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id="foo"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 738108 **/
+is(document.querySelector("#foo"), $("foo"),
+ "querySelector on document should find element by id")
+is($("content").querySelector("#foo"), $("foo"),
+ "querySelector on parent element should find element by id")
+is($("foo").querySelector("#foo"), null,
+ "querySelector on element should not find the element itself by id")
+
+is(document.querySelectorAll("#foo").length, 1,
+ "querySelectorAll on document should find element by id")
+is($("content").querySelectorAll("#foo").length, 1,
+ "querySelectorAll on parent element should find element by id")
+is($("foo").querySelectorAll("#foo").length, 0,
+ "querySelectorall on element should not find the element itself by id")
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug744830.html b/dom/base/test/test_bug744830.html
new file mode 100644
index 0000000000..2f9b3dc3c5
--- /dev/null
+++ b/dom/base/test/test_bug744830.html
@@ -0,0 +1,132 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=744830
+-->
+<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=166235">Mozilla Bug 166235</a>
+<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
+<pre id="test">
+<script type="application/javascript">
+ var t = document.getElementById('testnodes');
+ is(t.innerHTML,
+ "<span>hi</span> there <!-- mon ami -->",
+ "comment nodes should be included");
+
+ var PI = document.createProcessingInstruction('foo', 'bar="1.0"');
+ t.appendChild(PI);
+ is(t.innerHTML, '<span>hi</span> there <!-- mon ami --><?foo bar="1.0">',
+ "pi nodes should be included");
+
+ t.innerHTML = null;
+ t.appendChild(document.createElement("textarea"));
+ t.firstChild.appendChild(document.createTextNode("\nhello"));
+ // This is the old behavior. Spec requires something else.
+ is(t.innerHTML, "<textarea>\nhello</textarea>",
+ "No extra newlines should be inserted to the textarea!");
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg:svg"));
+ t.firstChild.textContent = "<foo>";
+ is(t.innerHTML, "<svg>&lt;foo&gt;</svg>");
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math:math"));
+ t.firstChild.textContent = "<foo>";
+ is(t.innerHTML, "<math>&lt;foo&gt;</math>");
+
+ // Prefix is serialized if element isn't HTML/SVG/MathML
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.example.org", "ex:example"));
+ t.firstChild.textContent = "<foo>";
+ is(t.innerHTML, "<ex:example>&lt;foo&gt;</ex:example>");
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.example.org", "example"));
+ t.firstChild.textContent = "<foo>";
+ is(t.innerHTML, "<example>&lt;foo&gt;</example>");
+
+ t.firstChild.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:lang", "us-en");
+ is(t.innerHTML, '<example xml:lang="us-en">&lt;foo&gt;</example>');
+
+ t.firstChild.setAttributeNS("http://www.w3.org/1999/xlink", "href", "foo");
+ is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo">&lt;foo&gt;</example>');
+
+ t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "http://foo");
+ is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo">&lt;foo&gt;</example>');
+
+ t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:bar", "http://bar");
+ is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo" xmlns:bar="http://bar">&lt;foo&gt;</example>');
+
+ t.firstChild.setAttributeNS("http://www.helloworldns.org", "hello:world", "!");
+ is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo" xmlns:bar="http://bar" hello:world="!">&lt;foo&gt;</example>');
+
+ t.firstChild.setAttribute("foo", '-"&\xA0-');
+ is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo" xmlns:bar="http://bar" hello:world="!" foo="-&quot;&amp;&nbsp;-">&lt;foo&gt;</example>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElement("div"));
+ t.firstChild.appendChild(document.implementation
+ .createDocument(null, null, null)
+ .createCDATASection("foo"));
+ is(t.innerHTML, '<div>foo</div>');
+
+ t.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<div>1&amp;2&lt;3&gt;4&nbsp;</div>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElement("script"));
+ t.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<script>1&2<3>4\xA0\u003C/script>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElement("style"));
+ t.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<style>1&2<3>4\xA0\u003C/style>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElement("span"));
+ t.firstChild.setAttributeNS("ext", "attr", "foo");
+ t.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<span attr="foo">1&amp;2&lt;3&gt;4&nbsp;\u003C/span>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
+ is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "script"));
+ is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<svg><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></svg>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
+ is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "style"));
+ is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+ t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<svg><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></svg>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
+ is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+ t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "script"));
+ is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+ t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<math><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></math>');
+
+ t.innerHTML = null;
+ t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
+ is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+ t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "style"));
+ is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+ t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+ is(t.innerHTML, '<math><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></math>');
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_bug749367.html b/dom/base/test/test_bug749367.html
new file mode 100644
index 0000000000..be017b71ba
--- /dev/null
+++ b/dom/base/test/test_bug749367.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=749367
+-->
+
+<head>
+ <title>Test for Bug 749367</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=749367">Mozilla Bug 749367</a>
+<div id="content" style="display: none"></div>
+ <pre id="test">
+
+ <script type="text/template">
+ ok(false, "Shouldn't execute");
+ </script>
+
+ <script type="text/javascript">
+ ok(true, "Should execute");
+ </script>
+
+ </pre>
+</body>
+
+</html>
diff --git a/dom/base/test/test_bug750096.html b/dom/base/test/test_bug750096.html
new file mode 100644
index 0000000000..adbff360a5
--- /dev/null
+++ b/dom/base/test/test_bug750096.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=750096
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 750096</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=750096">Mozilla Bug 750096</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 750096 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var u = SpecialPowers.Ci.nsIParserUtils;
+var s = SpecialPowers.ParserUtils;
+
+var elt = document.getElementById("content");
+
+var embed = s.parseFragment("<embed src=\'javascript:this.fail = true;\'>", 0, false, null, elt);
+var img = s.parseFragment("<img src=\'javascript:this.fail = true;\'>", 0, false, null, elt);
+var video = s.parseFragment("<video src=\'javascript:this.fail = true;\'></video>", 0, false, null, elt);
+var object = s.parseFragment("<object data=\'javascript:this.fail = true;\'></object>", 0, false, null, elt);
+var iframe = s.parseFragment("<iframe src=\'javascript:this.fail = true;\'></iframe>", 0, false, null, elt);
+
+setTimeout(function() {
+ ok(!window.fail, "Should not have failed.");
+ SimpleTest.finish();
+}, 0);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug753278.html b/dom/base/test/test_bug753278.html
new file mode 100644
index 0000000000..e65cd6c346
--- /dev/null
+++ b/dom/base/test/test_bug753278.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=753278
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 753278</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=753278">Mozilla Bug 753278</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 753278 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var f = document.getElementsByTagName("iframe")[0];
+
+function runTest() {
+ f.contentDocument.open();
+ f.contentDocument.write('<script>window.location = "file_bug753278.html"; document.close(); document.open(); document.write("\\u003Cscript>parent.fail();\\u003C/script>"); document.close();\u003c/script>');
+ f.contentDocument.close();
+}
+
+function pass() {
+ ok(true, "window.location took precedence");
+ SimpleTest.finish();
+}
+
+function fail() {
+ ok(false, "window.location should have taken precedence");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug761120.html b/dom/base/test/test_bug761120.html
new file mode 100644
index 0000000000..f3709ef692
--- /dev/null
+++ b/dom/base/test/test_bug761120.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=761120
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 761120</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=761120">Mozilla Bug 761120</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 761120 **/
+var doc = document.implementation.createHTMLDocument("title");
+try {
+ doc.appendChild(doc.createTextNode("text"));
+ ok(false, "Didn't throw");
+} catch (e) {
+ is(e.name, "HierarchyRequestError");
+}
+
+var el = document.createElement("div");
+var text = document.createTextNode("text");
+el.appendChild(text);
+is(el.firstChild, text);
+
+var df = document.createDocumentFragment();
+text = document.createTextNode("text");
+df.appendChild(text);
+is(df.firstChild, text);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug769117.html b/dom/base/test/test_bug769117.html
new file mode 100644
index 0000000000..eb59ade174
--- /dev/null
+++ b/dom/base/test/test_bug769117.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=769117
+ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 769117</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ /** Test for Bug 769117 **/
+ "use strict";
+ function onLoad () {
+ SpecialPowers.pushPrefEnv({"set": [["plugins.rewrite_youtube_embeds", true]]}, function() {
+
+ let youtube_url = "https://mochitest.youtube.com/v/Xm5i5kbIXzc";
+ let youtube_changed_url = "https://mochitest.youtube.com/embed/Xm5i5kbIXzc";
+ let static_iframe = document.getElementById("staticiframe");
+
+ function testEmbed(embed) {
+ ok (embed, "Embed node exists");
+ embed = SpecialPowers.wrap(embed);
+ is (embed.srcURI.spec, youtube_changed_url, "Should have src uri of " + youtube_changed_url);
+ }
+
+ function testStatic() {
+ info("Running static embed youtube rewrite test");
+ iframe_doc = static_iframe.contentWindow.document;
+ testEmbed(iframe_doc.getElementById("testembed"));
+ testEmbed(iframe_doc.getElementById("testobject"));
+ SimpleTest.executeSoon(() => {
+ testEmbed(embed_dynamic);
+ SimpleTest.finish();
+ });
+ }
+
+ info("Running dynamic embed youtube rewrite test");
+ let embed_dynamic = document.createElement("embed");
+ embed_dynamic.src = "https://mochitest.youtube.com/v/Xm5i5kbIXzc";
+ embed_dynamic.type = "application/x-shockwave-flash";
+ document.body.appendChild(embed_dynamic);
+
+ static_iframe.onload = testStatic;
+ static_iframe.src = "file_bug769117.html"
+
+ });
+ }
+ </script>
+ </head>
+ <body onload="onLoad()">
+ <iframe id="staticiframe"></iframe>
+ </body>
+</html>
diff --git a/dom/base/test/test_bug782342.html b/dom/base/test/test_bug782342.html
new file mode 100644
index 0000000000..9816ae173a
--- /dev/null
+++ b/dom/base/test/test_bug782342.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=782342
+-->
+<head>
+ <title>Test for bug 782342 - blob: protocol no Content-Length header</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=782342">Mozilla Bug 782342 - blob: protocol no Content-Length header</a>
+<p id="display">
+ <input id="fileList" type="file"></input>
+</p>
+
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var url = "file_bug782342.txt";
+var xhr = new XMLHttpRequest();
+xhr.open("GET", url, true);
+xhr.responseType = "blob";
+
+function checkHeaders(xhrInner) {
+ var headers = xhrInner.getAllResponseHeaders();
+ dump(headers + "\n");
+ var p = headers.split("\n");
+
+ var contentType = false;
+ var contentLength = false;
+
+ for (var i = 0; i < p.length; ++i) {
+ var header = p[i].split(':')[0];
+ if (header.toLowerCase() == 'content-type')
+ contentType = true;
+ else if (header.toLowerCase() == 'content-length')
+ contentLength = true;
+ }
+
+ ok(contentLength == true, "Content-length is part of the headers!");
+ ok(contentType == true, "Content-type is part of the headers!");
+
+ var ct = xhrInner.getResponseHeader('content-type');
+ ok(ct.length, 'Get Response Header - content type: ' + ct);
+ var cl = xhrInner.getResponseHeader('content-length');
+ ok(cl.length, 'Get Response Header - content length: ' + cl);
+}
+
+xhr.addEventListener("load", function () {
+ ok(xhr.status === 200, "Status 200!");
+ if (xhr.status === 200) {
+ var blob = xhr.response;
+ ok(blob, "Blob is: " + blob);
+ var blobUrl = window.URL.createObjectURL(blob);
+ ok(blobUrl, "Blob URL is: " + blobUrl);
+ checkHeaders(xhr);
+
+ var xhrBlob = new XMLHttpRequest();
+ xhrBlob.open("GET", blobUrl, true);
+ xhrBlob.responseType = "blob";
+
+ xhrBlob.addEventListener("load", function () {
+ var blob2 = xhr.response;
+ ok(blob2, "Blob is: " + blob2);
+ var blob2Url = window.URL.createObjectURL(blob);
+ ok(blob2Url, "Blob URL is: " + blob2Url);
+ checkHeaders(xhrBlob);
+
+ ok(blob2.size == blob.size, "Blob sizes are: " + blob2.size + " - " + blob.size);
+ ok(blob2.type == blob.type, "Blob types are: " + blob2.type + " - " + blob.type);
+
+ SimpleTest.finish();
+ });
+ xhrBlob.send();
+ }
+});
+xhr.send();
+</script>
+</body>
+
+</html>
diff --git a/dom/base/test/test_bug787778.html b/dom/base/test/test_bug787778.html
new file mode 100644
index 0000000000..4322b4567b
--- /dev/null
+++ b/dom/base/test/test_bug787778.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=787778
+ -->
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 787778</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ window.onload = function() {
+ window.document.x.src='a';
+ SimpleTest.executeSoon(function () {
+ ok(true, "Didn't crash!");
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </head>
+ <body>
+ <embed name="x" src="./file_bug787778.sjs">
+ </body>
+</html>
diff --git a/dom/base/test/test_bug789315.html b/dom/base/test/test_bug789315.html
new file mode 100644
index 0000000000..58516a8f45
--- /dev/null
+++ b/dom/base/test/test_bug789315.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=789315
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 789315</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ (function() {
+ const observerConfig = {
+ childList: true,
+ };
+
+ var observer = new MutationObserver(onMutations);
+ observer.observe(document.head, observerConfig);
+
+ function onMutations(mutations) {
+ for (var i in mutations) {
+ var mutation = mutations[i];
+ for (var j in mutation.addedNodes) {
+ var addedNode = mutation.addedNodes[j];
+ addedNode.mutationObserverHasNotified = true;
+ }
+ }
+ }
+
+ })();
+ </script>
+
+ <link id="testnode" rel="localization" href="dummy"></link>
+
+ <script type="text/javascript">
+ var testNode = document.getElementById("testnode");
+ ok(testNode.mutationObserverHasNotified);
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=789315">Mozilla Bug 789315</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug789856.html b/dom/base/test/test_bug789856.html
new file mode 100644
index 0000000000..3e62232bfc
--- /dev/null
+++ b/dom/base/test/test_bug789856.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=789856
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 789856</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=789856">Mozilla Bug 789856</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 789856 **/
+SimpleTest.waitForExplicitFinish();
+
+var script = document.createElement("script");
+script.onload = function() {
+ ok(false, "This script should not load");
+ SimpleTest.finish();
+}
+script.onerror = function() {
+ ok(true, "This script should fail to load");
+ SimpleTest.finish();
+}
+// If neither one fires, the test fails, as it should
+
+// Use a URL the test is not allowed to load
+script.src = "file:///tmp/"
+document.body.appendChild(script);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug809003.html b/dom/base/test/test_bug809003.html
new file mode 100644
index 0000000000..9c29392ea5
--- /dev/null
+++ b/dom/base/test/test_bug809003.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=809003
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 809003</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ #testdiv:before {
+ content: url('data:image/gif,GIF89a%01%00%01%00%80%01%00%FF%00%00%FF%FF%FF!%F9%04%01%00%00%01%00%2C%00%00%00%00%01%00%01%00%00%02%02D%01%00%3B');
+ }
+ #testdiv:after {
+ content: url('non_existing_image.gif');
+ }
+ </style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=809003">Mozilla Bug 809003</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 809003 **/
+
+window.didGetLoad = false;
+window.didGetError = false;
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+setTimeout(function() {
+ is(window.didGetLoad, false, "Shouldn't have got load event!");
+ is(window.didGetError, false, "Shouldn't have got error event!");
+ SimpleTest.finish();
+}, 1000);
+
+</script>
+</pre>
+<div id="testdiv" onload="window.didGetLoad = true;" onerror="window.didGetError = true;"></div>
+</body>
+</html>
diff --git a/dom/base/test/test_bug810494.html b/dom/base/test/test_bug810494.html
new file mode 100644
index 0000000000..7750211326
--- /dev/null
+++ b/dom/base/test/test_bug810494.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=810494
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 810494</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/SpecialPowers.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=810494">Mozilla Bug 810494</a>
+<pre id="test">
+<script type="application/javascript">
+
+function test(tag, type) {
+ "use strict";
+ info("testing " + tag + " tag with type " + type);
+
+ const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+ let obj = document.createElement(tag);
+ obj.type = type;
+ document.body.appendChild(obj);
+
+ obj instanceof OBJLC;
+ obj = SpecialPowers.wrap(obj);
+
+ // We expect this tag to simply go to alternate content, not get a
+ // pluginProblem binding or fire any events.
+ ok(obj.displayedType == OBJLC.TYPE_NULL, "expected null type");
+}
+
+// Test all non-plugin types these tags can load to make sure none of them
+// trigger plugin-specific fallbacks when loaded with no URI
+test("object", "text/html"); // Document
+test("object", "image/png"); // Image
+test("object", "image/svg+xml"); // SVG Document
+
+test("embed", "image/png"); // Image
+test("embed", "image/svg+xml"); // SVG Document
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug811701.html b/dom/base/test/test_bug811701.html
new file mode 100644
index 0000000000..993ad81475
--- /dev/null
+++ b/dom/base/test/test_bug811701.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=811701
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 811701</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=811701">Mozilla Bug 811701</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<math><mtext>test</mtext></math>
+<svg><polygon points="0,0 100,100 200,300"/></svg>
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+
+ /** Test for Bug 811701 **/
+ var math = document.querySelector("math");
+ is(math.innerHTML, "<mtext>test</mtext>", "<math> should have innerHTML");
+ is(math.outerHTML, "<math><mtext>test</mtext></math>",
+ "<math> should have innerHTML");
+ math.innerHTML = "<mo>+</mo>";
+ is(math.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML",
+ "Should have the right namespace after setting innerHTML on <math>");
+
+ var polygon = document.querySelector("polygon");
+ is(polygon.parentNode.innerHTML,
+ '<polygon points="0,0 100,100 200,300"></polygon>',
+ "<svg> should have innerHTML");
+ is(polygon.parentNode.outerHTML,
+ '<svg><polygon points="0,0 100,100 200,300"></polygon></svg>',
+ "<svg> should have outerHTML");
+ is(polygon.outerHTML, '<polygon points="0,0 100,100 200,300"></polygon>',
+ "<polygon> should have outerHTML");
+
+ var svg = document.querySelector("svg");
+ svg.innerHTML = "<rect/>";
+ is(svg.firstChild.namespaceURI, "http://www.w3.org/2000/svg",
+ "Should have the right namespace after setting innerHTML on <svg>");
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug811701.xhtml b/dom/base/test/test_bug811701.xhtml
new file mode 100644
index 0000000000..8986bac3e7
--- /dev/null
+++ b/dom/base/test/test_bug811701.xhtml
@@ -0,0 +1,52 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=811701
+-->
+<head>
+ <title>Test for Bug 811701</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=811701">Mozilla Bug 811701</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<math xmlns="http://www.w3.org/1998/Math/MathML"><mtext>test</mtext></math>
+<svg xmlns="http://www.w3.org/2000/svg"><polygon points="0,0 100,100 200,300"/></svg>
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+ <![CDATA[
+
+
+ /** Test for Bug 811701 **/
+ var math = document.querySelector("math");
+ is(math.innerHTML,
+ '<mtext xmlns="http://www.w3.org/1998/Math/MathML">test</mtext>',
+ "<math> should have innerHTML");
+ is(math.outerHTML,
+ '<math xmlns="http://www.w3.org/1998/Math/MathML"><mtext>test</mtext></math>',
+ "<math> should have innerHTML");
+ math.innerHTML = "<mo>+</mo>";
+ is(math.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML",
+ "Should have the right namespace after setting innerHTML on <math>");
+
+ var polygon = document.querySelector("polygon");
+ is(polygon.parentNode.innerHTML,
+ '<polygon xmlns="http://www.w3.org/2000/svg" points="0,0 100,100 200,300"/>',
+ "<svg> should have innerHTML");
+ is(polygon.parentNode.outerHTML,
+ '<svg xmlns="http://www.w3.org/2000/svg"><polygon points="0,0 100,100 200,300"/></svg>',
+ "<svg> should have outerHTML");
+ is(polygon.outerHTML, '<polygon xmlns="http://www.w3.org/2000/svg" points="0,0 100,100 200,300"/>',
+ "<polygon> should have outerHTML");
+
+ var svg = document.querySelector("svg");
+ svg.innerHTML = "<rect/>";
+ is(svg.firstChild.namespaceURI, "http://www.w3.org/2000/svg",
+ "Should have the right namespace after setting innerHTML on <math>");
+ ]]>
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug813919.html b/dom/base/test/test_bug813919.html
new file mode 100644
index 0000000000..f81fc9f410
--- /dev/null
+++ b/dom/base/test/test_bug813919.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=813919
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 813919</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=813919">Mozilla Bug 813919</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 813919 **/
+
+ function testDataNode(dataNode) {
+ var div = document.createElement("div");
+ div.appendChild(dataNode);
+ var span = document.createElement("span");
+ div.appendChild(span);
+ var r = document.createRange();
+ r.setStart(dataNode, 0);
+ r.setEnd(div, div.childNodes.length);
+ r.deleteContents();
+ ok(r.collapsed, "Range should be collapsed!");
+ is(r.startContainer, div, "startContainer should be div.");
+ is(r.startOffset, div.childNodes.length,
+ "Range should be collaped to the end of the div element.");
+ }
+
+ testDataNode(document.createProcessingInstruction("x", "x"));
+ testDataNode(document.createComment("x"));
+ testDataNode(document.createTextNode("x"));
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug814576.html b/dom/base/test/test_bug814576.html
new file mode 100644
index 0000000000..62d19e1c48
--- /dev/null
+++ b/dom/base/test/test_bug814576.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=814576
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 814576</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=814576">Mozilla Bug 814576</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 814576 **/
+var xhr = new XMLHttpRequest();
+xhr.open("GET", "");
+xhr.send();
+var called = false;
+// Add an event listener that only listens for trusted events
+xhr.addEventListener("abort", function() { called = true; }, false, false);
+
+// Check that synthetic events don't trigger the listener
+var ev = document.createEvent("Events");
+ev.initEvent("abort", false, false);
+xhr.dispatchEvent(ev);
+is(called, false, "Should not call listener for untrusted events");
+
+// And now make sure we get our abort
+xhr.abort();
+is(called, true, "Should call listener when we abort");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug819051.html b/dom/base/test/test_bug819051.html
new file mode 100644
index 0000000000..2d6bc500f0
--- /dev/null
+++ b/dom/base/test/test_bug819051.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=819051
+-->
+<head>
+ <title>Test for Bug 819051</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="test_headers_append();">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var url = "http://mochi.test:8888/tests/dom/base/test/bug819051.sjs";
+
+function test_headers_append()
+{
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url);
+ xhr.setRequestHeader("X-appended-to-this", "True");
+ xhr.setRequestHeader("X-appended-to-this", "False");
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4) {
+ is(xhr.getResponseHeader("X-appended-result"), "True, False", "Headers should have been appended.");
+ test_headers_clear();
+ }
+ }
+
+ xhr.send();
+}
+
+function test_headers_clear()
+{
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url);
+ xhr.setRequestHeader("X-appended-to-this", "True");
+ xhr.setRequestHeader("Accept", "foo/bar");
+
+ xhr.open("GET", url);
+ xhr.setRequestHeader("X-appended-to-this", "True");
+ xhr.setRequestHeader("Accept", "bar/foo");
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4) {
+ is(xhr.getResponseHeader("X-Accept-Result"), "bar/foo", "Set headers record should have been cleared by open.");
+ SimpleTest.finish();
+ }
+ }
+
+ xhr.send();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug820909.html b/dom/base/test/test_bug820909.html
new file mode 100644
index 0000000000..90ce908d34
--- /dev/null
+++ b/dom/base/test/test_bug820909.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=820909
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 820909</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=820909">Mozilla Bug 820909</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <span dÄ°sabled="CAPS"></span>
+</div>
+<pre id="test">
+<script>
+ var bogusScriptRan = false;
+</script>
+<script type="applÄ°cation/javascript">
+ bogusScriptRan = true;
+</script>
+<script type="application/javascript">
+
+/** Test for Bug 820909 **/
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 1
+ok(!bogusScriptRan, "Script types should be ASCII case-insensitive");
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 2
+var input = document.createElement("input");
+input.type = "radÄ°o";
+is(input.type, "text", "Input types should be ASCII case-insensitive");
+
+// XXX Not sure how to test items 3, 4, 5
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 6
+is(document.querySelector("[dÄ°sabled='caps']"), null,
+ "Checking whether an attribute is case-sensitive for selector-matching " +
+ "purposes should be ASCII case-insensitive on the attr name");
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 7
+$("content").style.width = "0";
+$("content").style.width = "1Ä°n";
+is($("content").style.width, "0px",
+ "CSS unit names should be ASCII case-insensitive");
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 8
+$("content").style.setProperty("animation-name", "a");
+$("content").style.setProperty("-moz-anÄ°mation-name", "b");
+is($("content").style.animationName, "a",
+ "CSS property aliases should be ASCII case-insensitive");
+
+// XXXbz don't know how to test item 9
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 10
+$("content").innerHTML = "<table><input type='hÄ°dden'></table>";
+is($("content").querySelector("input").parentNode, $("content"),
+ "Inputs that aren't actually type='hidden' should not be allowed as " +
+ "table kids");
+
+// XXXbz add test for item 11?
+
+// XXXbz add test for item 12?
+
+// Test for https://bugzilla.mozilla.org/show_bug.cgi?id=820909#c7 item 13
+$("content").style.setProperty("animation-name", "a");
+$("content").style.setProperty("anÄ°mation-name", "b");
+is($("content").style.animationName, "a",
+ "CSS property names should be ASCII case-insensitive");
+
+$("content").style.setProperty("display", "none");
+$("content").style.setProperty("display", "Ä°nline");
+is($("content").style.display, "none",
+ "CSS keywords should be ASCII case-insensitive");
+
+$("content").style.setProperty("color", "white");
+$("content").style.setProperty("color", "Ä°ndigo");
+is($("content").style.color, "white",
+ "CSS color names should be ASCII case-insensitive");
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug864595.html b/dom/base/test/test_bug864595.html
new file mode 100644
index 0000000000..15d210fa92
--- /dev/null
+++ b/dom/base/test/test_bug864595.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=864595
+-->
+<head>
+ <title>Test for Bug 864595</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=864595">Mozilla Bug 864595</a>
+<div id='editable' style='display:inline-block;'>abcd </div>
+<script type="application/javascript">
+/** Test for Bug 864595 **/
+var range = document.createRange();
+var elt = document.getElementById('editable');
+var eltRect = elt.getBoundingClientRect();
+
+var txtNode = elt.childNodes[0];
+range.setStart(txtNode, 0);
+range.setEnd(txtNode, 5);
+var rect = range.getBoundingClientRect();
+ok(rect.left >= eltRect.left && rect.right <= eltRect.right, "rect.left >= eltRect.left && rect.right <= eltRect.right");
+
+/* Put caret in the space */
+var caretPosX = rect.right + 10;
+var caretPosY = (rect.top + rect.bottom ) / 2;
+var caretRect = document.caretPositionFromPoint(caretPosX, caretPosY).getClientRect();
+ok(caretRect.right >= rect.right, "caretRect.right >= rect.right");
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug868999.html b/dom/base/test/test_bug868999.html
new file mode 100644
index 0000000000..e0dec1229c
--- /dev/null
+++ b/dom/base/test/test_bug868999.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=868999
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 868999</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=868999">Mozilla Bug 869006</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 868999 **/
+
+var r = new Range();
+ok(r, "Range has been created");
+
+var doc = document.implementation.createDocument("", "", null);
+var h1 = doc.createElement('h1');
+doc.appendChild(h1);
+
+var t = doc.createTextNode('Hello world');
+h1.appendChild(t);
+
+r.selectNodeContents(doc);
+is(r.toString(), "Hello world", "new Range() works!");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug869000.html b/dom/base/test/test_bug869000.html
new file mode 100644
index 0000000000..152c66de4f
--- /dev/null
+++ b/dom/base/test/test_bug869000.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=869000
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 869000</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=869000">Mozilla Bug 869006</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 869000 **/
+
+var c = new Text();
+ok(c, "Text has been created without content");
+is(c.data, "", "Text.data is ok");
+
+c = new Text('foo');
+ok(c, "Text has been created");
+is(c.data, "foo", "Text.data is ok");
+
+document.getElementById('display').appendChild(c);
+ok(true, "Text has been added to the document");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug869002.html b/dom/base/test/test_bug869002.html
new file mode 100644
index 0000000000..db9a63e754
--- /dev/null
+++ b/dom/base/test/test_bug869002.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=868999
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 868999</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=868999">Mozilla Bug 869002</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 868999 **/
+
+var d = new DocumentFragment();
+ok(d, "DocumentFragment has been created");
+
+document.appendChild(d);
+ok(true, "DocumentFragment has been added to the document");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug869006.html b/dom/base/test/test_bug869006.html
new file mode 100644
index 0000000000..78cca7b553
--- /dev/null
+++ b/dom/base/test/test_bug869006.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=869006
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 869006</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=869006">Mozilla Bug 869006</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 869006 **/
+
+var c = new Comment();
+ok(c, "Comment has been created without content");
+is(c.data, "", "Comment.data is ok");
+
+c = new Comment('foo');
+ok(c, "Comment has been created");
+is(c.data, "foo", "Comment.data is ok");
+
+document.appendChild(c);
+ok(true, "Comment has been added to the document");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug876282.html b/dom/base/test/test_bug876282.html
new file mode 100644
index 0000000000..0dc88d9ee1
--- /dev/null
+++ b/dom/base/test/test_bug876282.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=647518
+-->
+<head>
+ <title>Test for Bug 647518</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=647518">Mozilla Bug 647518</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 647518 **/
+SimpleTest.waitForExplicitFinish();
+var counter = 3;
+
+var called = false;
+var handle1 = window.requestAnimationFrame(function() {
+ called = true;
+});
+ok(handle1 > 0, "Should get back a nonzero handle");
+
+function checker() {
+ --counter;
+ if (counter == 0) {
+ is(called, false, "Canceled callback should not have been called");
+ SimpleTest.finish();
+ } else {
+ window.requestAnimationFrame(checker);
+ }
+}
+window.requestAnimationFrame(checker);
+window.cancelAnimationFrame(handle1);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug891952.html b/dom/base/test/test_bug891952.html
new file mode 100644
index 0000000000..4ec2e7a79b
--- /dev/null
+++ b/dom/base/test/test_bug891952.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=891952
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 891952</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 891952 **/
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(function() {
+ var all = document.all;
+ is(all.content, $("content"), "Should find the content");
+ ok(!("" in all), "Should not have an empty string prop on document.all");
+ is(all[""], undefined, "Should not get empty string on document.all");
+ is(all.namedItem(""), null,
+ "namedItem for empty string should return null on document.all");
+
+ var divs = document.getElementsByTagName("div");
+ ok(!("" in divs), "Should not have an empty string prop on getElementsByTagName");
+ is(divs[""], undefined, "Should not get empty string on getElementsByTagName");
+ is(divs.namedItem(""), null,
+ "namedItem for empty string should return null on getElementsByTagName");
+ var forms = document.forms;
+ ok(!("" in forms), "Should not have an empty string prop on document.forms");
+ is(forms[""], undefined, "Should not get empty string on document.forms");
+ is(forms.namedItem(""), null,
+ "namedItem for empty string should return null on document.forms");
+
+ var form = $("form");
+ ok(!("" in form), "Should not have an empty string prop on form");
+ is(form[""], undefined, "Should not get empty string on form");
+
+ var formEls = $("form").elements;
+ ok(!("" in formEls), "Should not have an empty string prop on form.elements");
+ is(formEls[""], undefined, "Should not get empty string on form.elements");
+ is(formEls.namedItem(""), null,
+ "namedItem for empty string should return null on form.elements");
+ SimpleTest.finish();
+ });
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=891952">Mozilla Bug 891952</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <div id=""></div>
+ <div name=""></div>
+ <form id="form" name="">
+ <input name="">
+ </form>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug894874.html b/dom/base/test/test_bug894874.html
new file mode 100644
index 0000000000..603738a9df
--- /dev/null
+++ b/dom/base/test/test_bug894874.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=894874
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 894874</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <!-- IMPORTANT: Keep the sheets in this order! -->
+ <link rel="stylesheet" type="text/css" href="data:text/css,">
+ <link rel="stylesheet" type="text/css" title="one" href="data:text/css,">
+ <link rel="stylesheet" type="text/css" title="two" href="data:text/css,">
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 894874 **/
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(function() {
+ is(document.styleSheets[0].disabled, false,
+ "Sheet with no title should be enabled");
+ is(document.styleSheets[1].disabled, false,
+ "First preferred sheet should be enabled");
+ is(document.styleSheets[2].disabled, true,
+ "Second preferred sheet should be disabled");
+ is(document.selectedStyleSheetSet, "one", "Sheet one is enabled");
+ document.styleSheets[0].disabled = true;
+ document.styleSheets[2].disabled = false;
+ ok(document.selectedStyleSheetSet === null,
+ "Sheet one and sheet two are both enabled");
+ SimpleTest.finish();
+ });
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=894874">Mozilla Bug 894874</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug895974.html b/dom/base/test/test_bug895974.html
new file mode 100644
index 0000000000..7077e2c996
--- /dev/null
+++ b/dom/base/test/test_bug895974.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=895974
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 895974</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 895974 **/
+ SimpleTest.waitForExplicitFinish();
+
+ addLoadEvent(function() {
+ var frag = document.createDocumentFragment();
+ var span = document.createElement("span");
+ var div = document.createElement("div");
+ var text = document.createTextNode("help");
+ frag.appendChild(document.createTextNode("fail"));
+ frag.appendChild(span);
+ frag.appendChild(text);
+ frag.appendChild(div);
+ frag.appendChild(document.createTextNode("fail"));
+
+ is(text.nextElementSibling, div, "nextElementSibling should work on text");
+ is(text.previousElementSibling, span,
+ "previousElementSibling should work on text");
+
+ is(document.firstElementChild, document.documentElement,
+ "firstElementChild should work on document");
+ is(document.lastElementChild, document.documentElement,
+ "lastElementChild should work on document");
+ is(document.children.length, 1, "Document has one element kid");
+ is(document.children[0], document.documentElement,
+ "Document only element child is <html>");
+
+ is(frag.firstElementChild, span,
+ "firstElementChild should work on document fragment");
+ is(frag.lastElementChild, div,
+ "lastElementChild should work on document fragment");
+ is(frag.children.length, 2, "Document fragment has two element kids");
+ is(frag.children[0], span, "Document fragment first element child is span");
+ is(frag.children[1], div, "Document fragment second element child is div");
+
+ is(document.documentElement.firstElementChild, document.head,
+ "firstElementChild should work on element");
+ is(document.documentElement.lastElementChild, document.body,
+ "lastElementChild should work on element");
+ is(document.documentElement.children.length, 2, "<html> has two element kids");
+ is(document.documentElement.children[0], document.head,
+ "<html> first element child is head");
+ is(document.documentElement.children[1], document.body,
+ "<html> second element child is body");
+ SimpleTest.finish();
+ });
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=895974">Mozilla Bug 895974</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug907892.html b/dom/base/test/test_bug907892.html
new file mode 100644
index 0000000000..31537aaee7
--- /dev/null
+++ b/dom/base/test/test_bug907892.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=907892
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 907892</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 907892 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var expectedMessages = 2;
+ window.onmessage = function (ev) {
+ if (ev.data.sandboxed) {
+ ok(ev.data.threw,
+ "Should have thrown when setting document.domain in sandboxed iframe");
+ } else {
+ ok(!ev.data.threw,
+ "Should not have thrown when setting document.domain in iframe");
+ }
+
+ --expectedMessages;
+ if (expectedMessages == 0) {
+ SimpleTest.finish();
+ }
+ };
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=907892">Mozilla Bug 907892</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<!-- Set all the sandbox flags to "allow" to make sure we cover that case -->
+<iframe
+ sandbox="allow-same-origin allow-scripts allow-forms allow-top-navigation alllow-pointer-lock"
+ src="http://test1.example.org/tests/dom/base/test/file_bug907892.html?sandboxed">
+</iframe>
+<iframe
+ src="http://test1.example.org/tests/dom/base/test/file_bug907892.html?normal">
+</iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug913761.html b/dom/base/test/test_bug913761.html
new file mode 100644
index 0000000000..6f08e5a1d2
--- /dev/null
+++ b/dom/base/test/test_bug913761.html
@@ -0,0 +1,40 @@
+
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=913761
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 913761 - basic support</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=913761">Mozilla Bug 913761</a>
+<script type="application/javascript">
+
+ var transportChannel = new MessageChannel();
+ transportChannel.port1.onmessage = function (event) {
+ ok(true, 'Port Returned.');
+ var portToService = event.data.port;
+ portToService.onmessage = function () {
+ ok(true, "message received");
+ SimpleTest.finish();
+ };
+ portToService.postMessage('READY?');
+ }
+
+ var serviceChannel = new MessageChannel();
+ serviceChannel.port1.onmessage = function (event) {
+ if (event.data == 'READY?') {
+ this.postMessage('READY!');
+ }
+ }
+
+ transportChannel.port2.postMessage({ port: serviceChannel.port2}, [serviceChannel.port2]);
+
+ SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug922681.html b/dom/base/test/test_bug922681.html
new file mode 100644
index 0000000000..16b91f70be
--- /dev/null
+++ b/dom/base/test/test_bug922681.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=922681
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 922681</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ function testInnerHTMLParserInsertionMode() {
+
+ function testInnerHTML(el, input, output) {
+ el.innerHTML = input;
+ is(el.innerHTML, output, el.tagName.toLowerCase() + ': "' + input + '"');
+ }
+
+ var c;
+
+ c = document.createElement("html");
+ testInnerHTML(c, "", "<head></head><body></body>");
+ testInnerHTML(c, "xyz", "<head></head><body>xyz</body>");
+ testInnerHTML(c, "<input>", "<head></head><body><input></body>");
+
+ c = document.createElement("colgroup");
+ testInnerHTML(c, "abcdef", "");
+ testInnerHTML(c, "", "");
+ testInnerHTML(c, "\n", "\n");
+ testInnerHTML(c, "<col>", "<col>");
+
+ c = document.createElement("select");
+ testInnerHTML(c, "123", "123");
+ testInnerHTML(c, "<input>", "");
+ testInnerHTML(c, "\0", "");
+ testInnerHTML(c, "<col>", "");
+ testInnerHTML(c, "<option>", "<option></option>");
+
+ c = document.createElement("head");
+ testInnerHTML(c, "123", "123");
+ testInnerHTML(c, "\n", "\n");
+
+ c = document.createElement("frameset");
+ testInnerHTML(c, "456", "");
+ testInnerHTML(c, "\n", "\n");
+ testInnerHTML(c, "<input>", "");
+ testInnerHTML(c, "\0", "");
+
+ c = document.createElement("table");
+ testInnerHTML(c, "abc", "abc");
+ testInnerHTML(c, "<td>", "<tbody><tr><td></td></tr></tbody>");
+ testInnerHTML(c, "</body>", "");
+ testInnerHTML(c, "<input>", "<input>");
+
+ c = document.createElement("tr");
+ testInnerHTML(c, "xyz", "xyz");
+ testInnerHTML(c, "<td>", "<td></td>");
+ testInnerHTML(c, "</body>", "");
+ testInnerHTML(c, "<table>", "");
+
+ c = document.createElement("td");
+ testInnerHTML(c, "789", "789");
+ testInnerHTML(c, "\0", "");
+ testInnerHTML(c, "<td>", "");
+
+ c = document.createElement("th");
+ testInnerHTML(c, "789", "789");
+ testInnerHTML(c, "\0", "");
+ testInnerHTML(c, "</tr>", "");
+
+ c = document.createElement("caption");
+ testInnerHTML(c, "xyz", "xyz");
+ testInnerHTML(c, "\0", "");
+ testInnerHTML(c, "<td>", "");
+ testInnerHTML(c, "<dd>", "<dd></dd>");
+ testInnerHTML(c, "<body>", "");
+
+ function testTableBody(tag) {
+ var e = document.createElement(tag);
+ testInnerHTML(e, "abc", "abc");
+ testInnerHTML(e, "<td>", "<tr><td></td></tr>");
+ testInnerHTML(e, "</body>", "");
+ testInnerHTML(e, "<input>", "<input>");
+ }
+ testTableBody("thead");
+ testTableBody("tbody");
+ testTableBody("tfoot");
+
+ c = document.createElement("template");
+ testInnerHTML(c, "abc", "abc");
+ testInnerHTML(c, "<td>", "<td></td>");
+ testInnerHTML(c, "</template>", "");
+ testInnerHTML(c, "<input>", "<input>");
+
+ c = document.createElement("div");
+ testInnerHTML(c, "abc", "abc");
+ testInnerHTML(c, "<td>", "");
+ testInnerHTML(c, "</body>", "");
+ testInnerHTML(c, "<input>", "<input>");
+
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(testInnerHTMLParserInsertionMode);
+ SimpleTest.waitForExplicitFinish();
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=922681">Mozilla Bug 922681</a>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug927196.html b/dom/base/test/test_bug927196.html
new file mode 100644
index 0000000000..3e1c829c57
--- /dev/null
+++ b/dom/base/test/test_bug927196.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=426308
+-->
+<head>
+ <title>Test for Bug 426308</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=927196">Mozilla Bug 927196</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 927196 **/
+
+function startTest() {
+ req = new XMLHttpRequest({mozSystem: true});
+ is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (3)");
+
+ req = new XMLHttpRequest({mozAnon: true});
+ is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (4)");
+ is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem (4)");
+
+ req = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+ is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (5)");
+ is(req.mozSystem, true, "XMLHttpRequest should be mozSystem (5)");
+
+ req = new XMLHttpRequest({mozAnon: false, mozSystem: true});
+ is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (6)");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+var req = new XMLHttpRequest({mozAnon: true});
+is(req.mozAnon, true, "XMLHttpRequest should be mozAnon");
+is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem");
+
+req = new XMLHttpRequest({mozAnon: true, mozSystem: true});
+is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (2)");
+is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem (2)");
+
+addLoadEvent(function() {
+ SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], startTest);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug945152.html b/dom/base/test/test_bug945152.html
new file mode 100644
index 0000000000..9075db0746
--- /dev/null
+++ b/dom/base/test/test_bug945152.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=945152
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 945152</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.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=945152">Mozilla Bug 945152</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+function translateChrome(uriStr) {
+ const { Cc, Ci } = SpecialPowers;
+ let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
+ let uri = ios.newURI(uriStr, null, ios.newURI(document.baseURI));
+ return chromeReg.convertChromeURL(uri).spec;
+}
+
+function runTest() {
+ var worker = new Worker("file_bug945152_worker.js");
+
+ worker.onmessage = function(event) {
+ if (event.data.type == 'finish') {
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ ok(false, "Worker had an error: " + event.filename + ":" + event.lineno + ":" + event.colno + ": " + event.message);
+ SimpleTest.finish();
+ };
+
+ worker.postMessage(translateChrome("file_bug945152.jar"));
+}
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.mapped_arraybuffer.enabled", true]]}, function() {
+ SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], runTest);
+ });
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug962251.html b/dom/base/test/test_bug962251.html
new file mode 100644
index 0000000000..fff381676c
--- /dev/null
+++ b/dom/base/test/test_bug962251.html
@@ -0,0 +1,244 @@
+
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=962251
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 962251</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+
+ function Test_ElementsInTheSameDocument() {
+ var button1 = document.getElementById("button1");
+ var button2 = document.getElementById("button2");
+
+ button1.focus();
+ is(button1.id, document.activeElement.id, "How did we call focus on button1 and it did" +
+ " not become the active element?");
+
+ var getBlurEvent = false;
+ button1.addEventListener("blur", function(aEvent) {
+ is(aEvent.target.id, "button1", "Button1 should lose focus.");
+ ok(aEvent.relatedTarget, "The relatedTarget should not be null.");
+ is(aEvent.relatedTarget.id, "button2", "The relatedTarget should be button2.");
+ getBlurEvent = true;
+ }, {once: true});
+
+ button2.addEventListener("focus", function(aEvent) {
+ ok(getBlurEvent, "Must get blur event first.");
+ is(aEvent.target.id, "button2", "Button2 should be focused.");
+ ok(aEvent.relatedTarget, "The relatedTarget should not be null.");
+ is(aEvent.relatedTarget.id, "button1", "The relatedTarget should be button1.");
+ button2.blur();
+ }, {once: true});
+
+ button2.addEventListener("blur", function(aEvent) {
+ is(aEvent.target.id, "button2", "Button2 should lose focus.");
+ ok(aEvent.relatedTarget === null, "The relatedTarget should be null.");
+ runTests();
+ }, {once: true});
+
+ button2.focus();
+ }
+
+ function Test_ElementsInDifferentDocument() {
+ var button2 = document.getElementById("button2");
+ button2.focus();
+ button2.addEventListener("blur", function(aEvent) {
+ is(aEvent.target.id, "button2", "Button2 should lose focus.");
+ ok(aEvent.relatedTarget === null, "The relatedTarget should be null, since it's in another document.");
+ }, {once: true});
+
+ var iframe = document.createElement("iframe");
+ iframe.id = "iframe";
+ iframe.src = "iframe_bug962251.html";
+ window.addEventListener("message", function(aEvent) {
+ if (aEvent.data == "runNextTest") {
+ runTests();
+ }
+ }, {once: true});
+ document.getElementById("content").appendChild(iframe);
+ }
+
+ function Test_FocusEventOnWindow() {
+ var iframe1 = document.createElement("iframe");
+ iframe1.id = "iframe1";
+ iframe1.src = "about:blank";
+
+ document.getElementById("content").appendChild(iframe1);
+ document.getElementById("button2").focus();
+ var iframe = document.getElementById("iframe");
+ var expectedEventTarget = [iframe.contentDocument, iframe.contentWindow];
+ var expectedEventTarget1 = [iframe1.contentDocument, iframe1.contentWindow];
+ iframe.contentWindow.addEventListener("focus", function onFocus(aEvent) {
+ var eventTarget = expectedEventTarget.shift();
+ ok(aEvent.target === eventTarget, "Get expected focus event target.");
+ ok(aEvent.relatedTarget === null, "relatedTarget should be null.");
+ if (!expectedEventTarget.length) {
+ iframe.contentWindow.removeEventListener("focus", onFocus, true);
+ runTests();
+ }
+ }, true);
+ iframe1.contentWindow.addEventListener("focus", function onFocus(aEvent) {
+ var eventTarget = expectedEventTarget1.shift();
+ ok(aEvent.target === eventTarget, "Get expected focus event target.");
+ ok(aEvent.relatedTarget === null, "relatedTarget should be null.");
+ if (!expectedEventTarget1.length) {
+ iframe1.contentWindow.removeEventListener("focus", onFocus, true);
+ // Append items for blur event listener
+ expectedEventTarget1.push(iframe1.contentDocument);
+ expectedEventTarget1.push(iframe1.contentWindow);
+ iframe.contentWindow.focus();
+ }
+ }, true);
+ iframe1.contentWindow.addEventListener("blur", function onBlur(aEvent) {
+ var eventTarget = expectedEventTarget1.shift();
+ ok(aEvent.target === eventTarget, "Get expected blur event target.");
+ ok(aEvent.relatedTarget === null, "relatedTarget should be null.");
+ if (!expectedEventTarget1.length) {
+ iframe1.contentWindow.removeEventListener("blur", onBlur, true);
+ }
+ }, true);
+ iframe1.contentWindow.focus();
+ }
+
+ function Test_SetFocusInBlurEvent() {
+ var button1 = document.getElementById("button1");
+ var button2 = document.getElementById("button2");
+ var button3 = document.getElementById("button3");
+
+ button1.focus();
+ is(button1.id, document.activeElement.id, "document.activeElement.id is button1");
+
+ button1.addEventListener("blur", function(aEvent) {
+ info("button1 blur");
+ is(aEvent.relatedTarget.id, button2.id, "relatedTarget.id should be button2.");
+ button3.focus();
+ }, {once: true});
+ button1.addEventListener("focus", function(aEvent) {
+ info("button1 focus");
+ }, {once: true});
+
+ button2.addEventListener("blur", function(aEvent) {
+ info("button2 blur");
+ }, {once: true});
+ button2.addEventListener("focus", function(aEvent) {
+ info("button2 focus");
+ }, {once: true});
+
+ button3.addEventListener("blur", function(aEvent) {
+ info("button3 blur");
+ }, {once: true});
+ button3.addEventListener("focus", function(aEvent) {
+ info("button3 focus");
+ ok(aEvent.relatedTarget === null, "aEvent.relatedTarget is null.");
+ runTests();
+ }, {once: true});
+
+ button2.focus();
+ }
+
+ function Test_ListenFocusBlurEventOnWindow1() {
+ var button2 = document.getElementById("button2");
+ button2.focus();
+
+ var iframe = document.getElementById("iframe");
+ var input = iframe.contentDocument.getElementById("textinput");
+ var expectedEventTarget = [button2, document, window];
+ var expectedEventTarget1 = [iframe.contentDocument, iframe.contentWindow, input];
+ window.addEventListener("blur", function onBlur(aEvent) {
+ var item = expectedEventTarget.shift();
+ ok(aEvent.target === item, "Get an expected blur event.");
+ ok(aEvent.relatedTarget === null, "relatedTarget should be null.");
+ if (!expectedEventTarget.length) {
+ iframe.contentWindow.removeEventListener("blur", onBlur, true);
+ }
+ }, true);
+ iframe.contentWindow.addEventListener("focus", function onFocus(aEvent) {
+ var item = expectedEventTarget1.shift();
+ ok(aEvent.target === item, "Get an expected focus event.");
+ ok(aEvent.relatedTarget === null, "relatedTarget should be null.");
+ if (!expectedEventTarget1.length) {
+ iframe.contentWindow.removeEventListener("focus", onFocus, true);
+ runTests();
+ }
+ }, true);
+
+ input.focus();
+ }
+
+ function Test_ListenFocusBlurEventOnWindow2() {
+ var iframe = document.getElementById("iframe");
+ var input = iframe.contentDocument.getElementById("textinput");
+ var input1 = iframe.contentDocument.getElementById("textinput1");
+
+ ok(iframe.contentDocument.activeElement === input, "Current focused element should be input.");
+ iframe.contentWindow.addEventListener("focus", function(aEvent) {
+ ok(aEvent.target === input1, "Input1 is focused.");
+ ok(aEvent.relatedTarget === input, "relatedTarget should be input.");
+ runTests();
+ }, {capture: true, once: true});
+ iframe.contentWindow.addEventListener("blur", function(aEvent) {
+ ok(aEvent.target === input, "Input is not focused.");
+ ok(aEvent.relatedTarget === input1, "relatedTarget should be input1.");
+ }, {capture: true, once: true});
+
+ input1.focus();
+ }
+
+ function Test_ListenFocusBlurEventOnWindow3() {
+ var iframe = document.getElementById("iframe");
+ var input1 = iframe.contentDocument.getElementById("textinput1");
+
+ ok(iframe.contentDocument.activeElement === input1, "Current focused element should be input1.");
+ iframe.contentWindow.addEventListener("blur", function(aEvent) {
+ ok(aEvent.target === input1, "Input1 is not focused.");
+ ok(aEvent.relatedTarget === null, "relatedTarget should be null.");
+ runTests();
+ }, {capture: true, once: true});
+
+ input1.blur();
+ }
+
+ var tests = [
+ Test_ElementsInTheSameDocument,
+ Test_ElementsInDifferentDocument,
+ Test_FocusEventOnWindow,
+ Test_SetFocusInBlurEvent,
+ Test_ListenFocusBlurEventOnWindow1,
+ Test_ListenFocusBlurEventOnWindow2,
+ Test_ListenFocusBlurEventOnWindow3
+ ];
+
+ function runTests()
+ {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ window.setTimeout(function () {
+ test();
+ });
+ }
+
+ </script>
+</head>
+<body onload="runTests();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=962251">Mozilla Bug 962251</a>
+<p id="display"></p>
+<div id="content">
+ <button id="button1">1</button>
+ <button id="button2">2</button>
+ <button id="button3">3</button>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/test_bug976673.html b/dom/base/test/test_bug976673.html
new file mode 100644
index 0000000000..ff656ef221
--- /dev/null
+++ b/dom/base/test/test_bug976673.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=976673
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 976673</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=976673">Mozilla Bug 976673</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<input id="input" onfocus="event.target.value = event.type;"
+ onblur="event.target.value = event.type;">
+<button id="button">set focus</button>
+<iframe id="iframe" src="http://example.org:80/tests/dom/base/test/iframe_bug976673.html"></iframe>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+// In e10s mode, ContentCacheInChild tries to retrieve selected text and
+// caret position when IMEContentObserver notifies IME of focus. At this time,
+// we hit assertion in ContentIterator.
+SimpleTest.expectAssertions(0, 6);
+
+window.addEventListener("mousedown", function (aEvent) { aEvent.preventDefault(); });
+
+function testSetFocus(aEventType, aCallback)
+{
+ var description = "Setting focus from " + aEventType + " handler: ";
+
+ var iframe = document.getElementById("iframe");
+ iframe.contentWindow.focus();
+
+ window.addEventListener("message", function (aEvent) {
+ is(aEvent.data, "input-value: focus",
+ description + "<input> in the iframe should get focus");
+
+
+ var input = document.getElementById("input");
+ input.value = "";
+
+ var button = document.getElementById("button");
+
+ var movingFocus = false;
+ button.addEventListener(aEventType,
+ function (event) {
+ movingFocus = true;
+ input.focus();
+ event.preventDefault();
+ button.removeEventListener(aEventType, arguments.callee, true);
+ }, true);
+
+ synthesizeMouseAtCenter(button, {});
+
+ window.addEventListener("message", function (event) {
+ if (movingFocus) {
+ is(event.data, "input-value: blur",
+ description + "<input> in the iframe should get blur");
+ is(input.value, "focus",
+ description + "<input> in the parent should get focus");
+ } else {
+ is(event.data, "input-value: focus",
+ description + "<input> in the iframe should keep having focus");
+ }
+
+ setTimeout(aCallback, 0);
+ }, {once: true});
+
+ iframe.contentWindow.postMessage("check", "*");
+ }, {once: true});
+
+ iframe.contentWindow.postMessage("init", "*");
+}
+
+function runTests()
+{
+ testSetFocus("mousedown",
+ function () {
+ testSetFocus("mouseup",
+ function () {
+ testSetFocus("click",
+ function () {
+ testSetFocus("DoNothing", // testing wihout moving focus by script
+ function () {
+ SimpleTest.finish();
+ });
+ });
+ });
+ });
+}
+
+SimpleTest.waitForFocus(runTests);
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_bug982153.html b/dom/base/test/test_bug982153.html
new file mode 100644
index 0000000000..c684c122e6
--- /dev/null
+++ b/dom/base/test/test_bug982153.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=982153
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 982153</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script>
+
+var sc = document.createElement("script");
+var error = null;
+sc.textContent = "try {\n reference_error; } catch(e) { error = e; }";
+document.documentElement.appendChild(sc);
+is(error.lineNumber, 2, "Error line number must be correct");
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982153">Mozilla Bug 982153</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_bug999456.html b/dom/base/test/test_bug999456.html
new file mode 100644
index 0000000000..ee1b3b5087
--- /dev/null
+++ b/dom/base/test/test_bug999456.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=999456
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 999456</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 999456 **/
+
+ SimpleTest.waitForExplicitFinish();
+ addEventListener("load", function (e) {
+ is(e.cancelable, false, "Load events should not be cancelable");
+ SimpleTest.finish();
+ });
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=999456">Mozilla Bug 999456</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_caretPositionFromPoint.html b/dom/base/test/test_caretPositionFromPoint.html
new file mode 100644
index 0000000000..5861ff685b
--- /dev/null
+++ b/dom/base/test/test_caretPositionFromPoint.html
@@ -0,0 +1,131 @@
+<!doctype html>
+<html>
+<!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=654352
+-->
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <title>Test for Bug 654352</title>
+ <style>
+ @font-face {
+ font-family: Ahem;
+ src: url("Ahem.ttf");
+ }
+
+ #a {
+ font-family: Ahem;
+ padding: 10px;
+ border: 8px solid black;
+ width: 450px;
+ }
+
+ #test5 {
+ height: 100px;
+ }
+
+ textarea, input {
+ -moz-appearance: none;
+ }
+ </style>
+<script>
+ function convertEmToPx(aEm) {
+ // Assumes our base font size is 16px = 12pt = 1.0em.
+ var pxPerEm = 16.0 / 1.0;
+ return pxPerEm * aEm;
+ }
+
+ function checkOffsetsFromPoint(aX, aY, aExpected, aElementName='no-name') {
+ var cp = document.caretPositionFromPoint(aX, aY);
+ if (!cp) {
+ ok(false, 'caretPositionFromPoint returned null for point: (' + aX + ', ' + aY + ')');
+ return;
+ }
+
+ ok(aExpected == cp.offset, 'expected offset at (' + aX + ', ' + aY + ') [' + aElementName + ']: ' + aExpected + ', got: ' + cp.offset);
+ }
+
+ function doTesting() {
+ var test1Element = document.getElementById("test1");
+ var test1Rect = test1Element.getBoundingClientRect();
+
+ // Check the first and last characters of the basic div.
+ checkOffsetsFromPoint(Math.round(test1Rect.left + 1), Math.round(test1Rect.top + 1), 0, 'test1');
+ checkOffsetsFromPoint(Math.round(test1Rect.left + test1Rect.width - 1), Math.round(test1Rect.top + 1), 13, 'test1');
+
+ // Check a middle character in the second line of the div.
+ // To do this, we calculate 7em in from the left of the bounding
+ // box, and convert this to PX. (Hence the reason we need the AHEM
+ // font).
+ var pixelsLeft = convertEmToPx(7);
+ var test2Element = document.getElementById("test2");
+ var test2Rect = test2Element.getBoundingClientRect();
+ checkOffsetsFromPoint(Math.round(test2Rect.left + pixelsLeft + 1), Math.round(test2Rect.top + 1), 7, 'test2');
+
+ // Check the first and last characters of the textarea.
+ var test3Element = document.getElementById('test3');
+ var test3Rect = test3Element.getBoundingClientRect();
+ checkOffsetsFromPoint(test3Rect.left + 5, test3Rect.top + 5, 0, 'test3');
+ checkOffsetsFromPoint(Math.round(test3Rect.left + test3Rect.width - 15), Math.round(test3Rect.top + 5), 3, 'test3');
+
+ // Check the first and last characters of the input.
+ var test4Element = document.getElementById('test4');
+ var test4Rect = test4Element.getBoundingClientRect();
+ checkOffsetsFromPoint(test4Rect.left + 5, test4Rect.top + 5, 0, 'test4');
+ checkOffsetsFromPoint(Math.round(test4Rect.left + test4Rect.width - 10), Math.round(test4Rect.top + 10), 6, 'test4');
+
+ // Check to make sure that x or y outside the viewport returns null.
+ var nullCp1 = document.caretPositionFromPoint(-10, 0);
+ ok(!nullCp1, "caret position with negative x should be null");
+ var nullCp2 = document.caretPositionFromPoint(0, -10);
+ ok(!nullCp2, "caret position with negative y should be null");
+ var nullCp3 = document.caretPositionFromPoint(9000, 0);
+ ok(!nullCp3, "caret position with x > viewport width should be null");
+ var nullCp4 = document.caretPositionFromPoint(0, 9000);
+ ok(!nullCp4, "caret position with x > viewport height should be null");
+
+ // Check a point within the bottom whitespace of the input.
+ var test5Element = document.getElementById('test5');
+ var test5Rect = test5Element.getBoundingClientRect();
+ var test5x = test5Rect.left + 5;
+ var test5y = test5Rect.bottom - 10;
+
+ todo(false, "test5Rect: (" + test5Rect.top + ", " + test5Rect.left + ", " + test5Rect.width + ", " + test5Rect.height + ")");
+ checkOffsetsFromPoint(test5x, test5y, 0, 'test5');
+
+ // Check the first and last characters of the numeric input.
+ var test6Element = document.getElementById("test6");
+ var test6Rect = test6Element.getBoundingClientRect();
+ checkOffsetsFromPoint(Math.round(test6Rect.left + 4),
+ Math.round(test6Rect.top + (test6Rect.height / 2)),
+ 0, "test6");
+ checkOffsetsFromPoint(Math.round(test6Rect.left + test6Rect.width - 36),
+ Math.round(test6Rect.top + (test6Rect.height / 2)),
+ 5, "test6");
+
+ // Check the first and last characters of the transformed div.
+ var test7Element = document.getElementById('test7');
+ var test7Rect = test7Element.getBoundingClientRect();
+ checkOffsetsFromPoint(Math.round(test7Rect.left + 1), Math.round(test7Rect.top + 1), 0, 'test7');
+ checkOffsetsFromPoint(Math.round(test7Rect.right - 1), Math.round(test7Rect.top + 1), 13, 'test7');
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+</script>
+</head>
+<body onload="doTesting();">
+<div id="a" contenteditable><span id="test1">abc, abc, abc</span><br>
+<span id="test2" style="color: blue;">abc, abc, abc</span><br>
+<textarea id="test3">abc</textarea><input id="test4" value="abcdef"><br><br>
+<marquee>marquee</marquee>
+<!-- Translate test7 while staying within confines of the test viewport -->
+<div id="test7" style="transform: translate(140px, -20px); display: inline-block;">abc, abc, abc</div>
+</div>
+<input id="test5" value="The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well. Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled `ORANGE MARMALADE', but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody, so managed to put it into one of the cupboards as she fell past it." type="text">
+<input id="test6" type="number" style="width:150px; height:57px;" value="31415"><br>
+</body>
+</html>
diff --git a/dom/base/test/test_change_policy.html b/dom/base/test/test_change_policy.html
new file mode 100644
index 0000000000..536b7ed776
--- /dev/null
+++ b/dom/base/test/test_change_policy.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test policies for Bug 1101288</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<!--
+This checks if the right policies are applied from a given string when the policy is changed after the document has been loaded.
+https://bugzilla.mozilla.org/show_bug.cgi?id=1101288
+-->
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * Listen for notifications from the child.
+ * These are sent in case of error, or when the loads we await have completed.
+ */
+window.addEventListener("message", function(event) {
+ if (event.data == "childLoadComplete") {
+ // all loads happen, continue the test.
+ advance();
+ }
+});
+
+/**
+ * helper to perform an XHR.
+ */
+function doXHR(aUrl, onSuccess, onFail) {
+ var xhr = new XMLHttpRequest();
+ xhr.responseType = "json";
+ xhr.onload = function () {
+ onSuccess(xhr);
+ };
+ xhr.onerror = function () {
+ onFail(xhr);
+ };
+ xhr.open('GET', aUrl, true);
+ xhr.send(null);
+}
+
+/**
+ * Grabs the results via XHR and passes to checker.
+ */
+function checkIndividualResults(aTestname, aExpectedReferrer, aName) {
+ doXHR('/tests/dom/base/test/referrer_change_server.sjs?action=get-test-results',
+ function(xhr) {
+ var results = xhr.response;
+ info(JSON.stringify(xhr.response));
+
+ for (i in aName) {
+ ok(aName[i] in results.tests, aName[i] + " tests have to be performed.");
+ is(results.tests[aName[i]].policy, aExpectedReferrer[i], aTestname + ' --- ' + results.tests[aName[i]].policy + ' (' + results.tests[aName[i]].referrer + ')');
+ }
+ advance();
+ },
+ function(xhr) {
+ ok(false, "Can't get results from the counter server.");
+ SimpleTest.finish();
+ });
+}
+
+function resetState() {
+ doXHR('/tests/dom/base/test/referrer_change_server.sjs?action=resetState',
+ advance,
+ function(xhr) {
+ ok(false, "error in reset state");
+ SimpleTest.finish();
+ });
+}
+
+
+/**
+ * This is the main test routine -- serialized by use of a generator.
+ * It resets the counter, then performs two tests in sequence using
+ * the same iframe.
+ */
+var tests = (function*() {
+ var iframe = document.getElementById("testframe");
+ var sjs = "/tests/dom/base/test/referrer_change_server.sjs?action=generate-policy-test";
+
+ yield SpecialPowers.pushPrefEnv(
+ { set: [["network.http.referer.disallowCrossSiteRelaxingDefault", false]] },
+ advance
+ );
+
+ yield resetState();
+ var name = "no-referrer-unsafe-url";
+ yield iframe.src = sjs + "&policy=" + escape('no-referrer') + "&name=" + name + "&newPolicy=" + escape('unsafe-url');
+ yield checkIndividualResults("unsafe-url (changed) with no-referrer first", ["full"], [name+'unsafe-url']);
+
+ yield resetState();
+ var name = "origin-no-referrer";
+ yield iframe.src = sjs + "&policy=" + escape('origin') + "&name=" + name + "&newPolicy=" + escape('no-referrer');
+ yield checkIndividualResults("no-referrer (changed) with origin first", ["none"], [name+'no-referrer']);
+
+ yield resetState();
+ var name = "unsafe-url-no-referrer";
+ yield iframe.src = sjs + "&policy=" + escape('unsafe-url') + "&name=" + name + "&newPolicy=" + escape('no-referrer');
+ yield checkIndividualResults("no-referrer (changed) with unsafe-url first", ["none"], [name+'no-referrer']);
+
+ sjs = "/tests/dom/base/test/referrer_change_server.sjs?action=generate-policy-test2";
+
+ yield resetState();
+ var name = "no-referrer-unsafe-url";
+ yield iframe.src = sjs + "&policy=" + escape('no-referrer') + "&name=" + name + "&newPolicy=" + escape('unsafe-url');
+ yield checkIndividualResults("unsafe-url (changed) with no-referrer first", ["full"], [name+'unsafe-url']);
+
+ yield resetState();
+ var name = "origin-no-referrer";
+ yield iframe.src = sjs + "&policy=" + escape('origin') + "&name=" + name + "&newPolicy=" + escape('no-referrer');
+ yield checkIndividualResults("no-referrer (changed) with origin first", ["none"], [name+'no-referrer']);
+
+ yield resetState();
+ var name = "unsafe-url-no-referrer";
+ yield iframe.src = sjs + "&policy=" + escape('unsafe-url') + "&name=" + name + "&newPolicy=" + escape('no-referrer');
+ yield checkIndividualResults("no-referrer (changed) with unsafe-url first", ["none"], [name+'no-referrer']);
+
+ // complete.
+ SimpleTest.finish();
+})();
+
+</script>
+</head>
+
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+
+</body>
+</html>
+
diff --git a/dom/base/test/test_clearTimeoutIntervalNoArg.html b/dom/base/test/test_clearTimeoutIntervalNoArg.html
new file mode 100644
index 0000000000..e1d60022fb
--- /dev/null
+++ b/dom/base/test/test_clearTimeoutIntervalNoArg.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for clearTimeout/clearInterval with no arguments not throwing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ clearTimeout();
+}, "clearTimeout with no args should not throw ");
+test(function() {
+ clearInterval();
+}, "clearInterval with no args should not throw ");
+</script>
diff --git a/dom/base/test/test_clipboard_nbsp.html b/dom/base/test/test_clipboard_nbsp.html
new file mode 100644
index 0000000000..a40c7246f6
--- /dev/null
+++ b/dom/base/test/test_clipboard_nbsp.html
@@ -0,0 +1,116 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=359303
+-->
+<head>
+ <meta charset="utf-8" />
+ <title>Test for copying non-breaking spaces to the clipboard</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=359303">Mozilla Bug 359303</a>
+
+<p id="display"></p>
+
+<div id="content">
+<!-- In a plain-text editable control (such as a textarea or textinput), copying to clipboard should
+preserve non-breaking spaces. -->
+<input
+ id="input-with-non-breaking-spaces"
+ value="Input content: This town is 100&nbsp;km away / «&nbsp;Est-ce Paris&nbsp;?&nbsp;» / Consecutive non-breaking spaces: '&nbsp;&nbsp;'">
+<textarea id="textarea-with-non-breaking-spaces">
+Textarea content:
+- This town is 100&nbsp;km away.
+- «&nbsp;Est-ce Paris&nbsp;?&nbsp;»
+- Consecutive non-breaking spaces: "&nbsp;&nbsp;"
+</textarea>
+
+<!-- In a content-editable div, copying to clipboard should preserve non-breaking spaces.
+However, for compatibility with what other browsers currently do, the behavior of replacing non-breaking spaces by spaces is preserved for now.
+See https://bugzilla.mozilla.org/show_bug.cgi?id=359303#c145
+-->
+<div contenteditable="true" id="content-editable-with-non-breaking-spaces">
+Content-editable content:
+- This town is 100&nbsp;km away.
+- «&nbsp;Est-ce Paris&nbsp;?&nbsp;»
+- Consecutive non-breaking spaces: "&nbsp;&nbsp;"
+</div>
+
+<!-- In non-editable HTML nodes, like this paragraph, copying to clipboard should preserve non-breaking
+spaces.
+However, for compatibility with what other browsers currently do, the behavior of replacing non-breaking spaces by spaces is preserved for now.
+See https://bugzilla.mozilla.org/show_bug.cgi?id=359303#c145
+-->
+<p id="paragraph-with-non-breaking-spaces">
+Paragraph content:
+- This town is 100&nbsp;km away.
+- «&nbsp;Est-ce Paris&nbsp;?&nbsp;»
+- Consecutive non-breaking spaces: "&nbsp;&nbsp;"
+</p>
+</div>
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+
+// Helper: for the given element, select all its content, execute a "Copy" command,
+// and return the text put into the clipboard.
+async function clipboardTextForElementId(aDomId, aExpectedString) {
+ let textContainer = document.getElementById(aDomId);
+ let sel = window.getSelection();
+ sel.removeAllRanges();
+
+ if (textContainer.select) {
+ // Select the entire text in the input or textarea
+ textContainer.select();
+ } else {
+ // Select text node in element.
+ let r = document.createRange();
+ r.setStart(textContainer, 0);
+ r.setEnd(textContainer, 1);
+ sel.addRange(r);
+ }
+
+ let copiedText = await SimpleTest.promiseClipboardChange(
+ function compare(aValue) {
+ return aValue.includes(aExpectedString);
+ },
+ function setup() {
+ synthesizeKey("C", {accelKey: true});
+ },
+ "text/plain");
+ return copiedText;
+}
+
+/** Test for Bug 359303 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async function() {
+ let iValue = await clipboardTextForElementId("input-with-non-breaking-spaces", "Input");
+ ok(iValue.includes("100 km"), "NBSP between two characters should be preserved");
+ ok(iValue.includes("« "), "A single NBSP near a punctuation mark should be preserved");
+ ok(iValue.includes(" »"), "A single NBSP near a punctuation mark should be preserved");
+ ok(iValue.includes(" ? "), "NBSPs before *and* after a character should be preserved");
+ ok(iValue.includes("  "), "Consecutive NBSPs should be preserved");
+
+ let tValue = await clipboardTextForElementId("textarea-with-non-breaking-spaces", "Textarea");
+ ok(tValue.includes("100 km"), "NBSP between two characters should be preserved");
+ ok(tValue.includes("« "), "A single NBSP near a punctuation mark should be preserved");
+ ok(tValue.includes(" »"), "A single NBSP near a punctuation mark should be preserved");
+ ok(tValue.includes(" ? "), "NBSPs before *and* after a character should be preserved");
+ ok(tValue.includes("  "), "Consecutive NBSPs should be preserved");
+
+ let cValue = await clipboardTextForElementId("content-editable-with-non-breaking-spaces", "Content-editable");
+ ok(cValue.includes("100 km"), "NBSP should be replaced by spaces, until brower compatibility issues are sorted out");
+
+ let pValue = await clipboardTextForElementId("paragraph-with-non-breaking-spaces", "Paragraph");
+ ok(pValue.includes("100 km"), "NBSP should be replaced by spaces, until brower compatibility issues are sorted out");
+
+ SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_constructor-assignment.html b/dom/base/test/test_constructor-assignment.html
new file mode 100644
index 0000000000..376e25fda3
--- /dev/null
+++ b/dom/base/test/test_constructor-assignment.html
@@ -0,0 +1,61 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript">
+function testConstructor(name)
+{
+ window[name] = 17; // resolve through assignment
+
+
+ var desc = Object.getOwnPropertyDescriptor(window, name);
+ ok(typeof desc === "object" && desc !== null, name + ": property must exist");
+
+ is(desc.value, 17, name + ": overwrite didn't work correctly");
+ is(desc.enumerable, false,
+ name + ": initial descriptor was non-enumerable, and [[Put]] changes " +
+ "the property value but not its enumerability");
+ is(desc.configurable, true,
+ name + ": initial descriptor was configurable, and [[Put]] changes the " +
+ "property value but not its configurability");
+ is(desc.writable, true,
+ name + ": initial descriptor was writable, and [[Put]] changes the " +
+ "property value but not its writability");
+}
+
+var ctors =
+ [
+ "HTMLElement",
+ "HTMLDivElement",
+ "HTMLSpanElement",
+ "HTMLParagraphElement",
+ "HTMLOptionElement",
+ "HTMLHtmlElement",
+ "Element",
+ "Node",
+ "Document",
+ "Image",
+ "Audio",
+ "HTMLAudioElement",
+ "HTMLVideoElement",
+ "Window",
+ "XMLHttpRequest",
+ "Navigator",
+ "WebSocket",
+ "Event",
+ "IDBKeyRange",
+ "CSSPageRule",
+ "SVGPatternElement",
+ ];
+
+ctors.forEach(testConstructor);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_constructor.html b/dom/base/test/test_constructor.html
new file mode 100644
index 0000000000..1a66d5b613
--- /dev/null
+++ b/dom/base/test/test_constructor.html
@@ -0,0 +1,61 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript">
+function testConstructor(name)
+{
+ window[name]; // resolve not through assignment
+ window[name] = 17;
+
+ var desc = Object.getOwnPropertyDescriptor(window, name);
+ ok(typeof desc === "object" && desc !== null, name + ": property must exist");
+
+ is(desc.value, 17, name + ": overwrite didn't work correctly");
+ is(desc.enumerable, false,
+ name + ": initial descriptor was non-enumerable, and [[Put]] changes " +
+ "the property value but not its enumerability");
+ is(desc.configurable, true,
+ name + ": initial descriptor was configurable, and [[Put]] changes the " +
+ "property value but not its configurability");
+ is(desc.writable, true,
+ name + ": initial descriptor was writable, and [[Put]] changes the " +
+ "property value but not its writability");
+}
+
+var ctors =
+ [
+ "HTMLElement",
+ "HTMLDivElement",
+ "HTMLSpanElement",
+ "HTMLParagraphElement",
+ "HTMLOptionElement",
+ "HTMLHtmlElement",
+ "Element",
+ "Node",
+ "Document",
+ "Image",
+ "Audio",
+ "HTMLAudioElement",
+ "HTMLVideoElement",
+ "Window",
+ "XMLHttpRequest",
+ "Navigator",
+ "WebSocket",
+ "Event",
+ "IDBKeyRange",
+ "CSSPageRule",
+ "SVGPatternElement",
+ ];
+
+ctors.forEach(testConstructor);
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_content_iterator_post_order.html b/dom/base/test/test_content_iterator_post_order.html
new file mode 100644
index 0000000000..cdd6f748e2
--- /dev/null
+++ b/dom/base/test/test_content_iterator_post_order.html
@@ -0,0 +1,875 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for post-order content iterator</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+function finish() {
+ // The SimpleTest may require usual elements in the template, but they shouldn't be during test.
+ // So, let's create them at end of the test.
+ document.body.innerHTML = '<div id="display"></div><div id="content"></div><pre id="test"></pre>';
+ SimpleTest.finish();
+}
+
+function createContentIterator() {
+ return Cc["@mozilla.org/scriptable-content-iterator;1"]
+ .createInstance(Ci.nsIScriptableContentIterator);
+}
+
+function getNodeDescription(aNode) {
+ if (aNode === undefined) {
+ return "undefine";
+ }
+ if (aNode === null) {
+ return "null";
+ }
+ function getElementDescription(aElement) {
+ if (aElement.tagName === "BR") {
+ if (aElement.previousSibling) {
+ return `<br> element after ${getNodeDescription(aElement.previousSibling)}`;
+ }
+ return `<br> element in ${getElementDescription(aElement.parentElement)}`;
+ }
+ let hasHint = aElement == document.body;
+ let tag = `<${aElement.tagName.toLowerCase()}`;
+ if (aElement.getAttribute("id")) {
+ tag += ` id="${aElement.getAttribute("id")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("class")) {
+ tag += ` class="${aElement.getAttribute("class")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("type")) {
+ tag += ` type="${aElement.getAttribute("type")}"`;
+ }
+ if (aElement.getAttribute("name")) {
+ tag += ` name="${aElement.getAttribute("name")}"`;
+ }
+ if (aElement.getAttribute("value")) {
+ tag += ` value="${aElement.getAttribute("value")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("style")) {
+ tag += ` style="${aElement.getAttribute("style")}"`;
+ hasHint = true;
+ }
+ if (hasHint) {
+ return tag + ">";
+ }
+ return `${tag}> in ${getElementDescription(aElement.parentElement)}`;
+ }
+ switch (aNode.nodeType) {
+ case aNode.TEXT_NODE:
+ return `text node, "${aNode.wholeText.replace(/\n/g, '\\n')}"`;
+ case aNode.COMMENT_NODE:
+ return `comment node, "${aNode.data.replace(/\n/g, '\\n')}"`;
+ case aNode.ELEMENT_NODE:
+ return getElementDescription(SpecialPowers.unwrap(aNode));
+ default:
+ return "unknown node";
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function () {
+ let iter = createContentIterator();
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with an empty element.
+ */
+ document.body.innerHTML = "<div></div>";
+ let description = "Initialized with empty <div> as root node:";
+ iter.initWithRootNode(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, document.body.firstChild);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with a range which selects empty element.
+ */
+ let range = document.createRange();
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with range including only empty <div>:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with positions which select empty element.
+ */
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with positions including only empty <div>:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with collapsed range in an empty element.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild, 0);
+ description = "Initialized with range collapsed in empty <div>:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range in an empty element.
+ */
+ description = "Initialized with a position in empty <div>:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ document.body.firstChild, 0, document.body.firstChild, 0);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with the text element.
+ */
+ document.body.innerHTML = "<div>some text.</div>";
+ description = "Initialized with a text node as root node:";
+ iter.initWithRootNode(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, document.body.firstChild.firstChild);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be the text node after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with a range which selects the text node.
+ */
+ range = document.createRange();
+ range.selectNode(document.body.firstChild.firstChild);
+ description = "Initialized with range including only text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first() and next() after initialized with positions which select the text node.
+ * XXX In this case, content iterator lists up the parent <div> element. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with positions including only text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> element after calling next() from first position (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling next() from first position`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() from second position (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next() from second position`);
+
+ /**
+ * Tests to initializing with collapsed range at start of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, 0);
+ description = "Initialized with range collapsed at start of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at start of a text node.
+ * XXX In this case, content iterator lists up the text node. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ description = "Initialized with a position at start of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, 0, document.body.firstChild.firstChild, 0);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with collapsed range at end of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ description = "Initialized with range collapsed at end of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at end of a text node.
+ * XXX In this case, content iterator lists up the text node. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ description = "Initialized with a position at end of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with collapsed range at middle of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2);
+ description = "Initialized with range collapsed at end of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at middle of a text node.
+ * XXX In this case, content iterator lists up the text node. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ description = "Initialized with a position at end of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with a range selecting all text in a text node.
+ */
+ range = document.createRange();
+ range.setStart(document.body.firstChild.firstChild, 0);
+ range.setEnd(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ description = "Initialized with range selecting all text in text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with positions selecting all text in a text node.
+ */
+ description = "Initialized with positions selecting all text in text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, 0,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic tests with complicated tree.
+ */
+ function check(aIter, aExpectedResult, aDescription) {
+ if (aExpectedResult.length) {
+ is(SpecialPowers.unwrap(aIter.currentNode), aExpectedResult[0],
+ `${aDescription}: currentNode should be the text node immediately after initialization (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(aExpectedResult[0])})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true immediately after initialization`);
+
+ aIter.first();
+ is(SpecialPowers.unwrap(aIter.currentNode), aExpectedResult[0],
+ `${aDescription}: currentNode should be the text node after calling first() (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(aExpectedResult[0])})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true after calling first()`);
+
+ for (let expected of aExpectedResult) {
+ is(SpecialPowers.unwrap(aIter.currentNode), expected,
+ `${aDescription}: currentNode should be the node (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(expected)})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true when ${getNodeDescription(expected)} is expected`);
+ aIter.next();
+ }
+
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null after calling next() finally (got: ${getNodeDescription(aIter.currentNode)}`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true after calling next() finally`);
+ } else {
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null immediately after initialization (got: ${getNodeDescription(aIter.currentNode)})`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true immediately after initialization`);
+
+ aIter.first();
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null after calling first() (got: ${getNodeDescription(aIter.currentNode)})`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true after calling first()`);
+ }
+ }
+
+ document.body.innerHTML = "<p>" +
+ "Here is <b>bold</b> and <i><u>underlined and </u>italic </i><span>or no style text.</span><br>" +
+ "</p>" +
+ "<p>" +
+ "Here is an &lt;input&gt; element: <input type=\"text\" value=\"default value\"><br>\n" +
+ "and a &lt;textarea&gt; element: <textarea>text area's text node</textarea><br><br>\n" +
+ "<!-- and here is comment node -->" +
+ "</p>";
+
+ let expectedResult =
+ [document.body.firstChild.firstChild, // the first text node
+ document.body.firstChild.firstChild.nextSibling.firstChild, // text in <b>
+ document.body.firstChild.firstChild.nextSibling, // <b>
+ document.body.firstChild.firstChild.nextSibling.nextSibling, // text next to <b>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.firstChild.firstChild, // text in <u>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.firstChild, // <u>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.firstChild.nextSibling, // text next to <u>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling, // <i>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.firstChild, // text in <span>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling, // <span>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // <br> next to <span>
+ document.body.firstChild, // first <p>
+ document.body.firstChild.nextSibling.firstChild, // the first text node in second <p>
+ document.body.firstChild.nextSibling.firstChild.nextSibling, // <input>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling, // <br> next to <input>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling, // text next to <input>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.firstChild, // text in <textarea>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling, // <textarea>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // <br> next to <textarea>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // <br> next to <br>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // text next to <br>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // comment
+ document.body.firstChild.nextSibling, // second <p>
+ document.body]; // <body>
+
+ iter.initWithRootNode(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, document.body);
+ check(iter, expectedResult, "Initialized with the <body> as root element:");
+
+ /**
+ * Selects the <body> with a range.
+ */
+ range = document.createRange();
+ range.selectNode(document.body);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter, expectedResult, "Initialized with range selecting the <body>");
+
+ /**
+ * Selects the <body> with positions.
+ */
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset, range.endContainer, range.endOffset);
+ check(iter, expectedResult, "Initialized with positions selecting the <body>");
+
+ /**
+ * Selects all children in the <body> with a range.
+ */
+ expectedResult.pop(); // <body> shouldn't be listed up.
+ range = document.createRange();
+ range.selectNodeContents(document.body);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter, expectedResult, "Initialized with range selecting all children in the <body>");
+
+ /**
+ * Selects all children in the <body> with positions.
+ */
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset, range.endContainer, range.endOffset);
+ check(iter, expectedResult, "Initialized with positions selecting all children in the <body>");
+
+ /**
+ * range/positions around elements.
+ */
+ document.body.innerHTML = "abc<b>def</b><i>ghi</i>jkl";
+ range = document.createRange();
+
+ range.setStart(document.body.firstChild, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '[abc<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '[abc<b>de]f'");
+
+ range.setStart(document.body.firstChild, 2);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting 'ab[c<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting 'ab[c<b>de]f'");
+
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting 'abc[<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting 'abc[<b>de]f'");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting 'abc{<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting 'abc{<b>de]f'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{de]f'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{def]</b>'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{def]</b>'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling, 1);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{def}</b>'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{def}</b>'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild, // text in <b>
+ document.body.firstChild.nextSibling], // <b>
+ "Initialized with range selecting '<b>{def</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild, // text in <b>
+ document.body.firstChild.nextSibling], // <b>
+ "Initialized with positions selecting '<b>{def</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling.firstChild, 3);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild, // text in <b>
+ document.body.firstChild.nextSibling], // <b>
+ "Initialized with range selecting '<b>def[</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild, // text in <b>
+ document.body.firstChild.nextSibling], // <b>
+ "Initialized with positions selecting '<b>def[</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <b>
+ "Initialized with range selecting '<b>def{</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <b>
+ "Initialized with positions selecting '<b>def{</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <b>
+ "Initialized with range selecting '<b>def{</b><i>}ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <b>
+ "Initialized with positions selecting '<b>def{</b><i>}ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling.firstChild, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with range selecting '<b>def{</b><i>]ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with positions selecting '<b>def{</b><i>]ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 0);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild, // text in <i>
+ document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with range selecting '<i>{ghi</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild, // text in <i>
+ document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with positions selecting '<i>{ghi</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling.firstChild, 3);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild, // text in <i>
+ document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with range selecting '<i>ghi[</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild, // text in <i>
+ document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with positions selecting '<i>ghi[</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 1);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with range selecting '<i>ghi{</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with positions selecting '<i>ghi{</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling, // <i>
+ document.body.firstChild.nextSibling.nextSibling.nextSibling], // text after <i>
+ "Initialized with range selecting '<i>ghi{</i>]jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling, // <i>
+ document.body.firstChild.nextSibling.nextSibling.nextSibling], // text after <i>
+ "Initialized with positions selecting '<i>ghi{</i>]jkl'");
+
+ /**
+ * range/positions around <br> elements.
+ */
+ document.body.innerHTML = "abc<br>def";
+ range = document.createRange();
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <br>
+ document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with range selecting 'abc[<br>]def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <br>
+ document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with positions selecting 'abc[<br>]def'");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with range selecting 'abc{<br>]def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with positions selecting 'abc{<br>]def'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with range selecting 'abc{<br>]def' (starting in <br>)");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with positions selecting 'abc{<br>]def' (starting in <br>)");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with range selecting 'abc{<br>}def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with positions selecting 'abc{<br>}def'");
+
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild], // text before <br>
+ "Initialized with range selecting 'abc[}<br>def' (ending in <br>)");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.POST_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild], // text before <br>
+ "Initialized with positions selecting 'abc[}<br>def' (ending in <br>)");
+
+ finish();
+});
+</script>
+</head>
+<body></body>
+</html>
diff --git a/dom/base/test/test_content_iterator_pre_order.html b/dom/base/test/test_content_iterator_pre_order.html
new file mode 100644
index 0000000000..4ad1832e9d
--- /dev/null
+++ b/dom/base/test/test_content_iterator_pre_order.html
@@ -0,0 +1,869 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for pre-order content iterator</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+function finish() {
+ // The SimpleTest may require usual elements in the template, but they shouldn't be during test.
+ // So, let's create them at end of the test.
+ document.body.innerHTML = '<div id="display"></div><div id="content"></div><pre id="test"></pre>';
+ SimpleTest.finish();
+}
+
+function createContentIterator() {
+ return Cc["@mozilla.org/scriptable-content-iterator;1"]
+ .createInstance(Ci.nsIScriptableContentIterator);
+}
+
+function getNodeDescription(aNode) {
+ if (aNode === undefined) {
+ return "undefine";
+ }
+ if (aNode === null) {
+ return "null";
+ }
+ function getElementDescription(aElement) {
+ if (aElement.tagName === "BR") {
+ if (aElement.previousSibling) {
+ return `<br> element after ${getNodeDescription(aElement.previousSibling)}`;
+ }
+ return `<br> element in ${getElementDescription(aElement.parentElement)}`;
+ }
+ let hasHint = aElement == document.body;
+ let tag = `<${aElement.tagName.toLowerCase()}`;
+ if (aElement.getAttribute("id")) {
+ tag += ` id="${aElement.getAttribute("id")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("class")) {
+ tag += ` class="${aElement.getAttribute("class")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("type")) {
+ tag += ` type="${aElement.getAttribute("type")}"`;
+ }
+ if (aElement.getAttribute("name")) {
+ tag += ` name="${aElement.getAttribute("name")}"`;
+ }
+ if (aElement.getAttribute("value")) {
+ tag += ` value="${aElement.getAttribute("value")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("style")) {
+ tag += ` style="${aElement.getAttribute("style")}"`;
+ hasHint = true;
+ }
+ if (hasHint) {
+ return tag + ">";
+ }
+ return `${tag}> in ${getElementDescription(aElement.parentElement)}`;
+ }
+ switch (aNode.nodeType) {
+ case aNode.TEXT_NODE:
+ return `text node, "${aNode.wholeText.replace(/\n/g, '\\n')}"`;
+ case aNode.COMMENT_NODE:
+ return `comment node, "${aNode.data.replace(/\n/g, '\\n')}"`;
+ case aNode.ELEMENT_NODE:
+ return getElementDescription(SpecialPowers.unwrap(aNode));
+ default:
+ return "unknown node";
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function () {
+ let iter = createContentIterator();
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with an empty element.
+ */
+ document.body.innerHTML = "<div></div>";
+ let description = "Initialized with empty <div> as root node:";
+ iter.initWithRootNode(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, document.body.firstChild);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with a range which selects empty element.
+ */
+ let range = document.createRange();
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with range including only empty <div>:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with positions which select empty element.
+ */
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with positions including only empty <div>:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with collapsed range in an empty element.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild, 0);
+ description = "Initialized with range collapsed in empty <div>:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range in an empty element.
+ */
+ description = "Initialized with a position in empty <div>:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ document.body.firstChild, 0, document.body.firstChild, 0);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with the text element.
+ */
+ document.body.innerHTML = "<div>some text.</div>";
+ description = "Initialized with a text node as root node:";
+ iter.initWithRootNode(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, document.body.firstChild.firstChild);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be the text node after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with a range which selects the text node.
+ */
+ range = document.createRange();
+ range.selectNode(document.body.firstChild.firstChild);
+ description = "Initialized with range including only text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first() and next() after initialized with positions which select the text node.
+ * XXX In this case, content iterator lists up the parent <div> element. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with positions including only text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> element immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> element after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling next() from first position (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling next() from first position`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() from second position (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next() from second position`);
+
+ /**
+ * Tests to initializing with collapsed range at start of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, 0);
+ description = "Initialized with range collapsed at start of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at start of a text node.
+ * XXX In this case, content iterator lists up the text node. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ description = "Initialized with a position at start of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, 0, document.body.firstChild.firstChild, 0);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with collapsed range at end of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ description = "Initialized with range collapsed at end of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at end of a text node.
+ * XXX In this case, content iterator lists up the text node. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ description = "Initialized with a position at end of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with collapsed range at middle of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2);
+ description = "Initialized with range collapsed at end of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at middle of a text node.
+ * XXX In this case, content iterator lists up the text node. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ description = "Initialized with a position at end of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with a range selecting all text in a text node.
+ */
+ range = document.createRange();
+ range.setStart(document.body.firstChild.firstChild, 0);
+ range.setEnd(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ description = "Initialized with range selecting all text in text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with positions selecting all text in a text node.
+ */
+ description = "Initialized with positions selecting all text in text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ document.body.firstChild.firstChild, 0,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic tests with complicated tree.
+ */
+ function check(aIter, aExpectedResult, aDescription) {
+ if (aExpectedResult.length) {
+ is(SpecialPowers.unwrap(aIter.currentNode), aExpectedResult[0],
+ `${aDescription}: currentNode should be the text node immediately after initialization (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(aExpectedResult[0])})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true immediately after initialization`);
+
+ aIter.first();
+ is(SpecialPowers.unwrap(aIter.currentNode), aExpectedResult[0],
+ `${aDescription}: currentNode should be the text node after calling first() (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(aExpectedResult[0])})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true after calling first()`);
+
+ for (let expected of aExpectedResult) {
+ is(SpecialPowers.unwrap(aIter.currentNode), expected,
+ `${aDescription}: currentNode should be the node (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(expected)})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true when ${getNodeDescription(expected)} is expected`);
+ aIter.next();
+ }
+
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null after calling next() finally (got: ${getNodeDescription(aIter.currentNode)}`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true after calling next() finally`);
+ } else {
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null immediately after initialization (got: ${getNodeDescription(aIter.currentNode)})`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true immediately after initialization`);
+
+ aIter.first();
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null after calling first() (got: ${getNodeDescription(aIter.currentNode)})`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true after calling first()`);
+ }
+ }
+
+ document.body.innerHTML = "<p>" +
+ "Here is <b>bold</b> and <i><u>underlined and </u>italic </i><span>or no style text.</span><br>" +
+ "</p>" +
+ "<p>" +
+ "Here is an &lt;input&gt; element: <input type=\"text\" value=\"default value\"><br>\n" +
+ "and a &lt;textarea&gt; element: <textarea>text area's text node</textarea><br><br>\n" +
+ "<!-- and here is comment node -->" +
+ "</p>";
+
+ let expectedResult =
+ [document.body, // <body>
+ document.body.firstChild, // first <p>
+ document.body.firstChild.firstChild, // the first text node
+ document.body.firstChild.firstChild.nextSibling, // <b>
+ document.body.firstChild.firstChild.nextSibling.firstChild, // text in <b>
+ document.body.firstChild.firstChild.nextSibling.nextSibling, // text next to <b>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling, // <i>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.firstChild, // <u>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.firstChild.firstChild, // text in <u>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.firstChild.nextSibling, // text next to <u>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling, // <span>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.firstChild, // text in <span>
+ document.body.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // <br> next to <span>
+ document.body.firstChild.nextSibling, // second <p>
+ document.body.firstChild.nextSibling.firstChild, // the first text node in second <p>
+ document.body.firstChild.nextSibling.firstChild.nextSibling, // <input>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling, // <br> next to <input>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling, // text next to <input>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling, // <textarea>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.firstChild, // text in <textarea>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // <br> next to <textarea>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // <br> next to <br>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, // text next to <br>
+ document.body.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling] // comment
+
+ iter.initWithRootNode(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, document.body);
+ check(iter, expectedResult, "Initialized with the <body> as root element");
+
+ /**
+ * Selects the <body> with a range.
+ */
+ range = document.createRange();
+ range.selectNode(document.body);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter, expectedResult, "Initialized with range selecting the <body>");
+
+ /**
+ * Selects the <body> with positions.
+ */
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset, range.endContainer, range.endOffset);
+ check(iter, expectedResult, "Initialized with positions selecting the <body>");
+
+ /**
+ * Selects all children in the <body> with a range.
+ */
+ expectedResult.shift(); // <body> shouldn't be listed up.
+ range = document.createRange();
+ range.selectNodeContents(document.body);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter, expectedResult, "Initialized with range selecting all children in the <body>");
+
+ /**
+ * Selects all children in the <body> with positions.
+ */
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset, range.endContainer, range.endOffset);
+ check(iter, expectedResult, "Initialized with positions selecting all children in the <body>");
+
+ /**
+ * range/positions around elements.
+ */
+ document.body.innerHTML = "abc<b>def</b><i>ghi</i>jkl";
+ range = document.createRange();
+
+ range.setStart(document.body.firstChild, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '[abc<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '[abc<b>de]f'");
+
+ range.setStart(document.body.firstChild, 2);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting 'ab[c<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting 'ab[c<b>de]f'");
+
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting 'abc[<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <b>
+ document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting 'abc[<b>de]f'");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting 'abc{<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <b>
+ document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting 'abc{<b>de]f'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{de]f'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{def]</b>'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{def]</b>'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling, 1);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{def}</b>'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{def}</b>'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{def</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{def</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling.firstChild, 3);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>def[</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>def[</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter, [],
+ "Initialized with range selecting '<b>def{</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [],
+ "Initialized with positions selecting '<b>def{</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with range selecting '<b>def{</b><i>}ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling], // <i>
+ "Initialized with positions selecting '<b>def{</b><i>}ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling.firstChild, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling, // <i>
+ document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with range selecting '<b>def{</b><i>]ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling, // <i>
+ document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with positions selecting '<b>def{</b><i>]ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 0);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with range selecting '<i>{ghi</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with positions selecting '<i>{ghi</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling.firstChild, 3);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with range selecting '<i>ghi[</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with positions selecting '<i>ghi[</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 1);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter, [],
+ "Initialized with range selecting '<i>ghi{</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [],
+ "Initialized with positions selecting '<i>ghi{</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.nextSibling], // text after <i>
+ "Initialized with range selecting '<i>ghi{</i>]jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.nextSibling], // text after <i>
+ "Initialized with positions selecting '<i>ghi{</i>]jkl'");
+
+ /**
+ * range/positions around <br> elements.
+ */
+ document.body.innerHTML = "abc<br>def";
+ range = document.createRange();
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // text before <br>
+ document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with range selecting 'abc[<br>]def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // text before <br>
+ document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with positions selecting 'abc[<br>]def'");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with range selecting 'abc{<br>]def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with positions selecting 'abc{<br>]def'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with range selecting 'abc{<br>]def' (starting in <br>)");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling, // <br>
+ document.body.firstChild.nextSibling.nextSibling], // text after <br>
+ "Initialized with positions selecting 'abc{<br>]def' (starting in <br>)");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with range selecting 'abc{<br>}def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with positions selecting 'abc{<br>}def'");
+
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild], // text before <br>
+ "Initialized with range selecting 'abc[}<br>def' (ending in <br>)");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.PRE_ORDER_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild], // text before <br>
+ "Initialized with positions selecting 'abc[}<br>def' (ending in <br>)");
+
+ finish();
+});
+</script>
+</head>
+<body></body>
+</html>
diff --git a/dom/base/test/test_content_iterator_subtree.html b/dom/base/test/test_content_iterator_subtree.html
new file mode 100644
index 0000000000..c6b311b3f6
--- /dev/null
+++ b/dom/base/test/test_content_iterator_subtree.html
@@ -0,0 +1,690 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for content subtree iterator</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+function finish() {
+ // The SimpleTest may require usual elements in the template, but they shouldn't be during test.
+ // So, let's create them at end of the test.
+ document.body.innerHTML = '<div id="display"></div><div id="content"></div><pre id="test"></pre>';
+ SimpleTest.finish();
+}
+
+function createContentIterator() {
+ return Cc["@mozilla.org/scriptable-content-iterator;1"]
+ .createInstance(Ci.nsIScriptableContentIterator);
+}
+
+function getNodeDescription(aNode) {
+ if (aNode === undefined) {
+ return "undefine";
+ }
+ if (aNode === null) {
+ return "null";
+ }
+ function getElementDescription(aElement) {
+ if (aElement.tagName === "BR") {
+ if (aElement.previousSibling) {
+ return `<br> element after ${getNodeDescription(aElement.previousSibling)}`;
+ }
+ return `<br> element in ${getElementDescription(aElement.parentElement)}`;
+ }
+ let hasHint = aElement == document.body;
+ let tag = `<${aElement.tagName.toLowerCase()}`;
+ if (aElement.getAttribute("id")) {
+ tag += ` id="${aElement.getAttribute("id")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("class")) {
+ tag += ` class="${aElement.getAttribute("class")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("type")) {
+ tag += ` type="${aElement.getAttribute("type")}"`;
+ }
+ if (aElement.getAttribute("name")) {
+ tag += ` name="${aElement.getAttribute("name")}"`;
+ }
+ if (aElement.getAttribute("value")) {
+ tag += ` value="${aElement.getAttribute("value")}"`;
+ hasHint = true;
+ }
+ if (aElement.getAttribute("style")) {
+ tag += ` style="${aElement.getAttribute("style")}"`;
+ hasHint = true;
+ }
+ if (hasHint) {
+ return tag + ">";
+ }
+ return `${tag}> in ${getElementDescription(aElement.parentElement)}`;
+ }
+ switch (aNode.nodeType) {
+ case aNode.TEXT_NODE:
+ return `text node, "${aNode.wholeText.replace(/\n/g, '\\n')}"`;
+ case aNode.COMMENT_NODE:
+ return `comment node, "${aNode.data.replace(/\n/g, '\\n')}"`;
+ case aNode.ELEMENT_NODE:
+ return getElementDescription(SpecialPowers.unwrap(aNode));
+ default:
+ return "unknown node";
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function () {
+ let iter = createContentIterator();
+
+ /**
+ * FYI: ContentSubtreeIterator does not support initWithRootNode() nor positionAt().
+ */
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with a range which selects empty element.
+ */
+ document.body.innerHTML = "<div></div>";
+ let range = document.createRange();
+ range.selectNode(document.body.firstChild);
+ let description = "Initialized with range including only empty <div>:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with positions which select empty element.
+ */
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with positions including only empty <div>:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Tests to initializing with collapsed range in an empty element.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild, 0);
+ description = "Initialized with range collapsed in empty <div>:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range in an empty element.
+ */
+ description = "Initialized with a position in empty <div>:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ document.body.firstChild, 0, document.body.firstChild, 0);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Basic behavior tests of first(), last(), prev() and next() after initialized with a range which selects the text node.
+ */
+ document.body.innerHTML = "<div>some text.</div>";
+ range = document.createRange();
+ range.selectNode(document.body.firstChild.firstChild);
+ description = "Initialized with range including only text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.last();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling last() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling last()`);
+
+ iter.prev();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling prev() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling prev()`); // XXX Is this expected?
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild.firstChild,
+ `${description} currentNode should be the text node after calling first() even after once done (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first() even after once done`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next()`);
+
+ /**
+ * Basic behavior tests of first() and next() after initialized with positions which select the text node.
+ * XXX In this case, content iterator lists up the parent <div> element. Not sure if this is intentional difference
+ * from initWithRange().
+ */
+ range.selectNode(document.body.firstChild);
+ description = "Initialized with positions including only text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> element immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), document.body.firstChild,
+ `${description} currentNode should be the <div> element after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(!iter.isDone, `${description} isDone shouldn't be true after calling first()`);
+
+ iter.next();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null after calling next() from first position (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true after calling next() from first position`);
+
+ /**
+ * Tests to initializing with collapsed range at start of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, 0);
+ description = "Initialized with range collapsed at start of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at start of a text node.
+ */
+ description = "Initialized with a position at start of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ document.body.firstChild.firstChild, 0, document.body.firstChild.firstChild, 0);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at end of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ description = "Initialized with range collapsed at end of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at end of a text node.
+ */
+ description = "Initialized with a position at end of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at middle of a text node.
+ */
+ range = document.createRange();
+ range.collapse(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2);
+ description = "Initialized with range collapsed at end of text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with collapsed range at middle of a text node.
+ */
+ description = "Initialized with a position at end of text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length / 2);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with a range selecting all text in a text node.
+ */
+ range = document.createRange();
+ range.setStart(document.body.firstChild.firstChild, 0);
+ range.setEnd(document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ description = "Initialized with range selecting all text in text node:";
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Tests to initializing with positions selecting all text in a text node.
+ */
+ description = "Initialized with positions selecting all text in text node:";
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ document.body.firstChild.firstChild, 0,
+ document.body.firstChild.firstChild, document.body.firstChild.firstChild.length);
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null immediately after initialization (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true immediately after initialization`);
+
+ iter.first();
+ is(SpecialPowers.unwrap(iter.currentNode), null,
+ `${description} currentNode should be null even after calling first() (got: ${getNodeDescription(iter.currentNode)})`);
+ ok(iter.isDone, `${description} isDone should be true even after calling first()`);
+
+ /**
+ * Basic tests with complicated tree.
+ */
+ function check(aIter, aExpectedResult, aDescription) {
+ if (aExpectedResult.length) {
+ is(SpecialPowers.unwrap(aIter.currentNode), aExpectedResult[0],
+ `${aDescription}: currentNode should be the text node immediately after initialization (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(aExpectedResult[0])})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true immediately after initialization`);
+
+ aIter.first();
+ is(SpecialPowers.unwrap(aIter.currentNode), aExpectedResult[0],
+ `${aDescription}: currentNode should be the text node after calling first() (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(aExpectedResult[0])})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true after calling first()`);
+
+ for (let expected of aExpectedResult) {
+ is(SpecialPowers.unwrap(aIter.currentNode), expected,
+ `${aDescription}: currentNode should be the node (got: ${getNodeDescription(aIter.currentNode)}, expected: ${getNodeDescription(expected)})`);
+ ok(!aIter.isDone, `${aDescription}: isDone shouldn't be true when ${getNodeDescription(expected)} is expected`);
+ aIter.next();
+ }
+
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null after calling next() finally (got: ${getNodeDescription(aIter.currentNode)}`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true after calling next() finally`);
+ } else {
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null immediately after initialization (got: ${getNodeDescription(aIter.currentNode)})`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true immediately after initialization`);
+
+ aIter.first();
+ is(SpecialPowers.unwrap(aIter.currentNode), null,
+ `${aDescription}: currentNode should be null after calling first() (got: ${getNodeDescription(aIter.currentNode)})`);
+ ok(aIter.isDone, `${aDescription}: isDone should be true after calling first()`);
+ }
+ }
+
+ document.body.innerHTML = "<p>" +
+ "Here is <b>bold</b> and <i><u>underlined and </u>italic </i><span>or no style text.</span><br>" +
+ "</p>" +
+ "<p>" +
+ "Here is an &lt;input&gt; element: <input type=\"text\" value=\"default value\"><br>\n" +
+ "and a &lt;textarea&gt; element: <textarea>text area's text node</textarea><br><br>\n" +
+ "<!-- and here is comment node -->" +
+ "</p>";
+
+ /**
+ * Selects the <body> with a range.
+ */
+ range = document.createRange();
+ range.selectNode(document.body);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [document.body], "Initialized with range selecting the <body>");
+
+ /**
+ * Selects the <body> with positions.
+ */
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset, range.endContainer, range.endOffset);
+ check(iter, [document.body], "Initialized with positions selecting the <body>");
+
+ /**
+ * Selects all children in the <body> with a range.
+ */
+ range = document.createRange();
+ range.selectNodeContents(document.body);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild, // first <p>
+ document.body.firstChild.nextSibling], // second <p>
+ "Initialized with range selecting all children in the <body>");
+
+ /**
+ * Selects all children in the <body> with positions.
+ */
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset, range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild, // first <p>
+ document.body.firstChild.nextSibling], // second <p>
+ "Initialized with positions selecting all children in the <body>");
+
+ /**
+ * range/positions around elements.
+ */
+ document.body.innerHTML = "abc<b>def</b><i>ghi</i>jkl";
+ range = document.createRange();
+
+ range.setStart(document.body.firstChild, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '[abc<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '[abc<b>de]f'");
+
+ range.setStart(document.body.firstChild, 2);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,[], "Initialized with range selecting 'ab[c<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting 'ab[c<b>de]f'");
+
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting 'abc[<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting 'abc[<b>de]f'");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting 'abc{<b>de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting 'abc{<b>de]f'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<b>{de]f'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<b>{de]f'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.firstChild, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<b>{def]</b>'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<b>{def]</b>'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling, 1);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{def}</b>'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{def}</b>'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with range selecting '<b>{def</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.firstChild], // text in <b>
+ "Initialized with positions selecting '<b>{def</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling.firstChild, 3);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<b>def[</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<b>def[</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<b>def{</b>}<i>ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<b>def{</b>}<i>ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<b>def{</b><i>}ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<b>def{</b><i>}ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling.firstChild, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<b>def{</b><i>]ghi'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<b>def{</b><i>]ghi'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 0);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with range selecting '<i>{ghi</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling.nextSibling.firstChild], // text in <i>
+ "Initialized with positions selecting '<i>{ghi</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling.firstChild, 3);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<i>ghi[</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<i>ghi[</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 1);
+ range.setEnd(document.body, 3);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<i>ghi{</i>}jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<i>ghi{</i>}jkl'");
+
+ range.setStart(document.body.firstChild.nextSibling.nextSibling, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting '<i>ghi{</i>]jkl'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting '<i>ghi{</i>]jkl'");
+
+ /**
+ * range/positions around <br> elements.
+ */
+ document.body.innerHTML = "abc<br>def";
+ range = document.createRange();
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with range selecting 'abc[<br>]def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with positions selecting 'abc[<br>]def'");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with range selecting 'abc{<br>]def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with positions selecting 'abc{<br>]def'");
+
+ range.setStart(document.body.firstChild.nextSibling, 0);
+ range.setEnd(document.body.firstChild.nextSibling.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting 'abc{<br>]def' (starting in <br>)");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting 'abc{<br>]def' (starting in <br>)");
+
+ range.setStart(document.body, 1);
+ range.setEnd(document.body, 2);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with range selecting 'abc{<br>}def'");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter,
+ [document.body.firstChild.nextSibling], // <br>
+ "Initialized with positions selecting 'abc{<br>}def'");
+
+ range.setStart(document.body.firstChild, 3);
+ range.setEnd(document.body.firstChild.nextSibling, 0);
+ iter.initWithRange(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR, range);
+ check(iter, [], "Initialized with range selecting 'abc[}<br>def' (ending in <br>)");
+ iter.initWithPositions(Ci.nsIScriptableContentIterator.SUBTREE_ITERATOR,
+ range.startContainer, range.startOffset,
+ range.endContainer, range.endOffset);
+ check(iter, [], "Initialized with positions selecting 'abc[}<br>def' (ending in <br>)");
+
+ finish();
+});
+</script>
+</head>
+<body></body>
+</html>
diff --git a/dom/base/test/test_copyimage.html b/dom/base/test/test_copyimage.html
new file mode 100644
index 0000000000..0badf940e5
--- /dev/null
+++ b/dom/base/test/test_copyimage.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=518249
+https://bugzilla.mozilla.org/show_bug.cgi?id=952456
+-->
+<head>
+ <title>Test for copy image</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=518249">Mozilla Bug 518249</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=952456">Mozilla Bug 952456</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function testCopyImage () {
+ var Ci = SpecialPowers.Ci;
+ var Cc = SpecialPowers.Cc;
+ var clipboard = SpecialPowers.Services.clipboard;
+
+ function getClipboardData(mime) {
+ var transferable = Cc['@mozilla.org/widget/transferable;1']
+ .createInstance(Ci.nsITransferable);
+ var loadingContext = SpecialPowers.wrap(window).docShell
+ .QueryInterface(Ci.nsILoadContext);
+ transferable.init(loadingContext);
+ transferable.addDataFlavor(mime);
+ clipboard.getData(transferable, 1);
+ var data = SpecialPowers.createBlankObject();
+ transferable.getTransferData(mime, data);
+ return data;
+ }
+
+ function testClipboardValue(mime, expected) {
+ var data = SpecialPowers.wrap(getClipboardData(mime));
+ var str = data.value == null ? data.value :
+ data.value.QueryInterface(Ci.nsISupportsString).data;
+ is(str, expected, "clipboard has correct [" + mime + "] content")
+ }
+
+ //--------- Prepare data and copy it.
+
+ // Select the node.
+ var node = document.getElementById('logo');
+
+ // Set node and copy image.
+ var docShell = SpecialPowers.wrap(window).docShell;
+ var documentViewer = docShell.contentViewer
+ .QueryInterface(Ci.nsIContentViewerEdit);
+ documentViewer.setCommandNode(node);
+ documentViewer.copyImage(documentViewer.COPY_IMAGE_ALL);
+
+ //--------- Let's check the content of the clipboard now.
+
+ // Does the clipboard contain text/plain data ?
+ ok(clipboard.hasDataMatchingFlavors(["text/plain"], 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");
+
+ // Is the text/plain data correct ?
+ testClipboardValue('text/plain', 'about:logo');
+ // Is the text/html data correct ?
+ var expected = '<img id="logo" src="about:logo">';
+ if (navigator.platform.includes("Win")) {
+ expected = kTextHtmlPrefixClipboardDataWindows + expected + kTextHtmlSuffixClipboardDataWindows;
+ }
+ testClipboardValue('text/html', expected);
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(testCopyImage);
+</script>
+</pre>
+<div>
+ <img id="logo" src="about:logo">
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_copypaste.html b/dom/base/test/test_copypaste.html
new file mode 100644
index 0000000000..014ac7f9dc
--- /dev/null
+++ b/dom/base/test/test_copypaste.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test for copy/paste</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="text/javascript" src="copypaste.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=524975">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(() => {
+ add_task(async function test_copyhtml() {
+ await testCopyPaste(false);
+ });
+});
+
+</script>
+</pre>
+<div>
+
+ <div id="draggable" title="title to have a long HTML line">This is a <em>draggable</em> bit of text.</div>
+ <textarea id="input" cols="40" rows="10"></textarea>
+
+ <div id="alist">
+ bla
+ <ul>
+ <li>foo</li>
+ <li style="display: none;">baz</li>
+ <li>bar</li>
+ </ul>
+ </div>
+
+ <div id="blist">
+ mozilla
+ <ol>
+ <li>foo</li>
+ <li style="display: none;">baz</li>
+ <li>bar</li>
+ </ol>
+ </div>
+
+ <div id="clist">
+ mzla
+ <ul>
+ <li>foo<ul>
+ <li>bazzinga!</li>
+ </ul></li>
+ <li style="display: none;">baz</li>
+ <li>bar</li>
+ </ul>
+ </div>
+
+<div id="div4">
+ T<textarea>t t t</textarea>
+</div>
+
+<div id="div5">
+ T<textarea> </textarea>
+</div>
+
+<div>Copy1then Paste<ul id="ul1"><li>LI</li>
+</ul></div>
+
+<div><ul id="ul2">
+<li>LI</li></ul>Copy2then Paste</div>
+
+<div><ul id="ul3"><li>
+<li>LI</li></ul>Copy3then Paste</div>
+
+<div><div id="div1s"><div id="div1se1">before<div>inner</div></div>after</div></div>
+<div><div id="div2s"><div id="div2se1">before<div>inner</div></div>after</div>
+</div>
+
+<div id="contentEditable1" contenteditable spellcheck="false"></div>
+<div id="contentEditable2" contenteditable spellcheck="false"></div>
+<div id="contentEditable3" contenteditable spellcheck="false"></div>
+<div id="contentEditable4" contenteditable spellcheck="false"></div>
+<div id="contentEditable5" contenteditable spellcheck="false"></div>
+
+<div>
+<span id="1127835crash1">1</span><div id="1127835crash2"><div>
+</div></div><a href="http://www.mozilla.org/" id="1127835crash3">3</a>
+</div>
+<div id="contentEditable6" contenteditable spellcheck="false"></div>
+
+<div id="div6" style="display:none"></div>
+<script>
+var x = $("div6")
+x.appendChild(document.createTextNode('di'))
+x.appendChild(document.createTextNode('v6'))
+</script>
+
+<div id="div7" style="display:none">div7</div>
+<div id="div8" style="visibility:hidden">div8</div>
+<div style="visibility:hidden"><div id="div9" style="visibility:visible">div9</div></div>
+<div style="visibility:hidden"><div><div><div id="div10"></div></div></div></div>
+<script>
+var x = $("div10")
+x.appendChild(document.createTextNode('div'))
+x.appendChild(document.createTextNode('10'))
+</script>
+
+<div id="div11" oncopy="modifySelection('X')"><span>div</span>11</div>
+<div id="div12" oncopy="modifySelection('X<b style=\'display:none\'>Y</b>')"><span>div</span>12</div>
+
+<div id="div13">_<noscript>FAIL</noscript>_</div>
+
+<table><tr id=tr1><td>foo</td><td>bar</td></tr></table>
+<table><tr id=tr2><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr><tr id=tr3><td>5</td><td>6</td></tr></table>
+
+<div>X<ruby id="ruby1"><rb>aa</rb><rb>bb</rb><rp>(</rp><rt>AA</rt><rt>BB</rt><rp>)</rp></ruby>Y</div>
+
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_copypaste.xhtml b/dom/base/test/test_copypaste.xhtml
new file mode 100644
index 0000000000..ebc1371560
--- /dev/null
+++ b/dom/base/test/test_copypaste.xhtml
@@ -0,0 +1,112 @@
+<?xml version="1.0"?>
+<!--
+This test is copied from test_copypaste.html, but it's XHTML instead of HTML.
+XHTML is encoded differently from HTML when copied; see bugs 888839 and 723163.
+This test is different from test_copypaste.html in two ways:
+
+ 1. The text/html clipboard flavor isn't tested, since nsCopySupport doesn't
+ produce it for XHTML.
+ 2. The text/plain flavor isn't tested when the selection is in hidden
+ elements, since nsCopySupport doesn't produce text/plain for hidden
+ elements, and unlike HTML, neither does it produce text/_moz_htmlcontext
+ and text/_moz_htmlinfo, which the clipboard converts to text/plain.
+-->
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Test for copy/paste with XHTML</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="copypaste.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=888839">Mozilla Bug 888839</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+function modifySelectionDiv12() {
+ modifySelection("X<b style='display:none'>Y</b>");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(() => {
+ add_task(async function test_copyhtml() {
+ await testCopyPaste(true);
+ });
+});
+
+]]>
+</script>
+</pre>
+<div>
+
+ <div id="draggable" title="title to have a long HTML line">This is a <em>draggable</em> bit of text.</div>
+ <textarea id="input" cols="40" rows="10"></textarea>
+
+ <div id="alist">
+ bla
+ <ul>
+ <li>foo</li>
+ <li style="display: none;">baz</li>
+ <li>bar</li>
+ </ul>
+ </div>
+
+ <div id="blist">
+ mozilla
+ <ol>
+ <li>foo</li>
+ <li style="display: none;">baz</li>
+ <li>bar</li>
+ </ol>
+ </div>
+
+ <div id="clist">
+ mzla
+ <ul>
+ <li>foo<ul>
+ <li>bazzinga!</li>
+ </ul></li>
+ <li style="display: none;">baz</li>
+ <li>bar</li>
+ </ul>
+ </div>
+
+<div id="div4">
+ T<textarea>t t t</textarea>
+</div>
+
+<div id="div5">
+ T<textarea> </textarea>
+</div>
+
+<div id="div6" style="display:none"></div>
+<script>
+var x = $("div6")
+x.appendChild(document.createTextNode('di'))
+x.appendChild(document.createTextNode('v6'))
+</script>
+
+<div id="div7" style="display:none">div7</div>
+<div id="div8" style="visibility:hidden">div8</div>
+<div style="visibility:hidden"><div id="div9" style="visibility:visible">div9</div></div>
+<div style="visibility:hidden"><div><div><div id="div10"></div></div></div></div>
+<script>
+var x = $("div10")
+x.appendChild(document.createTextNode('div'))
+x.appendChild(document.createTextNode('10'))
+</script>
+
+<div id="div11" oncopy="modifySelection('X')"><span>div</span>11</div>
+<div id="div12" oncopy="modifySelectionDiv12()"><span>div</span>12</div>
+
+<div id="div13">_<noscript>FAIL</noscript>_</div>
+
+<table><tr id="tr1"><td>foo</td><td>bar</td></tr></table>
+
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_copypaste_disabled.html b/dom/base/test/test_copypaste_disabled.html
new file mode 100644
index 0000000000..06dbdbc779
--- /dev/null
+++ b/dom/base/test/test_copypaste_disabled.html
@@ -0,0 +1,116 @@
+<!doctype html>
+<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="copypaste.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<div id="content">
+ <style>
+ @font-face {
+ font-family: Ahem;
+ src: url("Ahem.ttf");
+ }
+ body { font-family: Ahem; font-size: 20px; margin: 0; }
+ input, textarea {
+ font: inherit;
+ -moz-appearance: none;
+ padding: 0;
+ border: 0;
+ scrollbar-width: none;
+ }
+ </style>
+ <input id="disabled-input" disabled value="abcd"> efgh <br> <textarea rows=1 id="disabled-textarea" disabled>ijkl</textarea> mnop <br>
+</div>
+
+<script>
+function dragSelect(e, x1, x2, x3) {
+ dir = x2 > x1 ? 1 : -1;
+ synthesizeMouse(e, x1, 5, { type: "mousedown" });
+ synthesizeMouse(e, x1 + dir, 5, { type: "mousemove" });
+ if (x3)
+ synthesizeMouse(e, x3, 5, { type: "mousemove" });
+ synthesizeMouse(e, x2 - dir, 5, { type: "mousemove" });
+ synthesizeMouse(e, x2, 5, { type: "mouseup" });
+}
+
+SimpleTest.waitForExplicitFinish();
+waitUntilApzStable().then(async function() {
+ const docShell = SpecialPowers.wrap(window).docShell;
+
+ const clipboard = SpecialPowers.Services.clipboard;
+
+ function copySelectionToClipboard() {
+ return SimpleTest.promiseClipboardChange(
+ () => true,
+ () => {
+ SpecialPowers.doCommand(window, "cmd_copy");
+ }
+ );
+ }
+
+ function getLoadContext() {
+ return docShell.QueryInterface(SpecialPowers.Ci.nsILoadContext);
+ }
+
+ function getClipboardData(mime) {
+ var transferable = SpecialPowers.Cc[
+ "@mozilla.org/widget/transferable;1"
+ ].createInstance(SpecialPowers.Ci.nsITransferable);
+ transferable.init(getLoadContext());
+ transferable.addDataFlavor(mime);
+ clipboard.getData(transferable, 1);
+ var data = SpecialPowers.createBlankObject();
+ transferable.getTransferData(mime, data);
+ return data;
+ }
+
+ function testClipboardValue(mime, expected) {
+ var data = SpecialPowers.wrap(getClipboardData(mime));
+ is(
+ data.value == null
+ ? data.value
+ : data.value.QueryInterface(SpecialPowers.Ci.nsISupportsString).data,
+ expected,
+ mime + " value in the clipboard"
+ );
+ return data.value;
+ }
+
+ async function runTestsOn(doc) {
+ for (let id of ["disabled-input", "disabled-textarea"]) {
+ let element = doc.getElementById(id);
+ dragSelect(element, 0, 60);
+ await copySelectionToClipboard();
+ testClipboardValue("text/plain", element.value.substr(0, 3));
+ }
+ }
+
+ await runTestsOn(document)
+
+ let iframe = document.createElement("iframe");
+ iframe.setAttribute("frameborder", "0");
+ iframe.srcdoc = `<!doctype html>${document.getElementById("content").outerHTML}`;
+ let iframeLoad = new Promise(resolve => {
+ iframe.addEventListener("load", resolve, { once: true });
+ });
+ document.body.appendChild(iframe);
+
+ await iframeLoad;
+ iframe.width = window.innerWidth;
+ iframe.height = window.innerHeight;
+
+ await SimpleTest.promiseFocus(iframe.contentWindow);
+ await runTestsOn(iframe.contentDocument);
+
+ // Add a contenteditable element to test the case where there's an HTMLEditor
+ // around the page.
+ let div = document.createElement("div");
+ div.setAttribute("contenteditable", "true");
+ document.body.appendChild(div);
+
+ await runTestsOn(document);
+
+ SimpleTest.finish();
+});
+</script>
diff --git a/dom/base/test/test_createHTMLDocument.html b/dom/base/test/test_createHTMLDocument.html
new file mode 100644
index 0000000000..66b090d189
--- /dev/null
+++ b/dom/base/test/test_createHTMLDocument.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<title>createHTMLDocument</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="http://www.whatwg.org/html5/#creating-documents">
+<link rel="help" href="http://www.whatwg.org/html5/#document.title">
+<link rel="help" href="http://www.whatwg.org/html5/#dom-document-readystate">
+<body>
+<script>
+function isElement(element, localName) {
+ is(element.localName, localName);
+ is(element.namespaceURI, "http://www.w3.org/1999/xhtml");
+ is(element.tagName, localName.toUpperCase());
+ is(element.nodeName, localName.toUpperCase());
+ is(element.prefix, null);
+}
+function checkDoc(title, expectedtitle, normalizedtitle) {
+ var doc = document.implementation.createHTMLDocument(title);
+ is(doc.readyState, "complete");
+ is(doc.compatMode, "CSS1Compat");
+ // Opera doesn't have a doctype: DSK-311092
+ ok(doc.doctype, "Need a doctype");
+ is(doc.doctype.name, "html");
+ is(doc.doctype.publicId, "");
+ is(doc.doctype.systemId, "");
+ isElement(doc.documentElement, "html");
+ isElement(doc.documentElement.firstChild, "head");
+ if (title !== undefined) {
+ is(doc.documentElement.firstChild.childNodes.length, 1);
+ isElement(doc.documentElement.firstChild.firstChild, "title");
+ // Doesn't always work out in WebKit.
+ ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
+ is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
+ } else {
+ is(doc.documentElement.firstChild.childNodes.length, 0);
+ }
+ isElement(doc.documentElement.lastChild, "body");
+ is(doc.documentElement.lastChild.childNodes.length, 0);
+ is(doc.title, normalizedtitle);
+ doc.body.innerHTML = "foo";
+ is(doc.body.innerHTML, "foo", "innerHTML should work in HTML data documents!");
+}
+checkDoc("", "", "");
+checkDoc(null, "null", "null");
+checkDoc(undefined, "", "");
+checkDoc("foo bar baz", "foo bar baz", "foo bar baz");
+checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz");
+checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz");
+checkDoc("foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz");
+checkDoc("foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz");
+</script>
diff --git a/dom/base/test/test_current_inner_window.html b/dom/base/test/test_current_inner_window.html
new file mode 100644
index 0000000000..3e7a700e63
--- /dev/null
+++ b/dom/base/test/test_current_inner_window.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test that current inner window checks are correct after navigations/discards</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<iframe id="frame"></iframe>
+
+<script type="application/javascript">
+"use strict";
+
+const TEST_FILE = "file_current_inner_window.html";
+const BASE_PATH = location.pathname.replace(/[^\/]+$/, "");
+
+let frame = document.getElementById("frame");
+
+function loadInFrame(url) {
+ return new Promise(resolve => {
+ frame.addEventListener("load", resolve, { once: true });
+ frame.contentWindow.location = url;
+ });
+}
+
+add_task(async function() {
+ await loadInFrame(TEST_FILE);
+
+ // Store the check function from the window before we navigate. After that,
+ // its bare word property accesses will continue referring to the same inner
+ // window no matter how many times the frame navigates.
+ let check1 = frame.contentWindow.isCurrentWinnerWindow;
+ ok(check1(),
+ "Initial inner window should be current before we navigate away");
+
+ await loadInFrame(`http://example.com/${BASE_PATH}/${TEST_FILE}`);
+ ok(!check1(),
+ "Initial inner window should no longer be current after we navigate away");
+ await SpecialPowers.spawn(frame, [], () => {
+ Assert.ok(this.content.wrappedJSObject.isCurrentWinnerWindow(),
+ "Remote inner window should be current after before we navigate away");
+ });
+
+ await loadInFrame(TEST_FILE);
+ ok(!check1(),
+ "Initial inner window should still not be current after we back to current process");
+ let check2 = frame.contentWindow.isCurrentWinnerWindow;
+ ok(check2(),
+ "Second in-process inner window should be current before we remove the frame");
+
+ frame.remove();
+ ok(!check1(),
+ "Initial inner window should still not be current after we remove the frame");
+ ok(check2(),
+ "Second in-process inner window should still be current after we remove the frame");
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_custom_element.html b/dom/base/test/test_custom_element.html
new file mode 100644
index 0000000000..7c87e0416f
--- /dev/null
+++ b/dom/base/test/test_custom_element.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ </head>
+ <body onload="startTests()">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129" target="_blank">Mozilla Bug 783129</a>
+ <iframe id="fooframe" src="/"></iframe>
+ <script type="application/javascript">
+
+ /** Test for Bug 783129 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function startTests() {
+ var frame = document.getElementById("fooframe");
+ class XFoo extends frame.contentWindow.HTMLElement {};
+ frame.contentWindow.customElements.define("x-foo", XFoo);
+ var elem = new XFoo();
+ is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
+
+ var anotherElem = $("fooframe").contentDocument.createElement("x-foo");
+ is(anotherElem.tagName, "X-FOO", "createElement should create an x-foo element.");
+ SimpleTest.finish();
+ }
+
+ </script>
+ </body>
+</html>
diff --git a/dom/base/test/test_custom_element_reflector.html b/dom/base/test/test_custom_element_reflector.html
new file mode 100644
index 0000000000..aa7bba3efe
--- /dev/null
+++ b/dom/base/test/test_custom_element_reflector.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<title>Custom Elements don't lose their reflectors</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<!-- First tests upgrading with an existing reflector, second without -->
+<custom-element></custom-element>
+<custom-element></custom-element>
+<script>
+ (function() {
+ // Ensure we create a reflector for the first element before-hand.
+ let firstElement = document.querySelector("custom-element");
+ }());
+
+ customElements.define("custom-element", class MyCustomElement extends HTMLElement {
+ myFunction() {
+ // Do nothing
+ }
+ });
+
+ ok(!!document.querySelector("custom-element").myFunction, "Has the right prototype before GC");;
+ ok(!!document.querySelectorAll("custom-element")[1].myFunction, "Has the right prototype before GC");;
+
+ SpecialPowers.forceCC();
+ SpecialPowers.forceGC();
+
+ ok(!!document.querySelector("custom-element").myFunction, "Has the right prototype after GC");;
+ ok(!!document.querySelectorAll("custom-element")[1].myFunction, "Has the right prototype before GC");;
+</script>
diff --git a/dom/base/test/test_data_uri.html b/dom/base/test/test_data_uri.html
new file mode 100644
index 0000000000..aa1c0fdbda
--- /dev/null
+++ b/dom/base/test/test_data_uri.html
@@ -0,0 +1,189 @@
+<html>
+<head>
+ <title>Tests for Data URI</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>
+ <style>
+ @font-face {
+ font-family: 'DataFont';
+ src: url(data:font/opentype;base64,AAEAAAANAIAAAwBQRkZUTU6u6MkAAAXcAAAAHE9TLzJWYWQKAAABWAAAAFZjbWFwAA8D7wAAAcAAAAFCY3Z0IAAhAnkAAAMEAAAABGdhc3D//wADAAAF1AAAAAhnbHlmCC6aTwAAAxQAAACMaGVhZO8ooBcAAADcAAAANmhoZWEIkAV9AAABFAAAACRobXR4EZQAhQAAAbAAAAAQbG9jYQBwAFQAAAMIAAAACm1heHAASQA9AAABOAAAACBuYW1lehAVOgAAA6AAAAIHcG9zdP+uADUAAAWoAAAAKgABAAAAAQAAMhPyuV8PPPUACwPoAAAAAMU4Lm0AAAAAxTgubQAh/5wFeAK8AAAACAACAAAAAAAAAAEAAAK8/5wAWgXcAAAAAAV4AAEAAAAAAAAAAAAAAAAAAAAEAAEAAAAEAAwAAwAAAAAAAgAAAAEAAQAAAEAALgAAAAAAAQXcAfQABQAAAooCvAAAAIwCigK8AAAB4AAxAQIAAAIABgkAAAAAAAAAAAABAAAAAAAAAAAAAAAAUGZFZABAAEEAQQMg/zgAWgK8AGQAAAABAAAAAAAABdwAIQAAAAAF3AAABdwAZAAAAAMAAAADAAAAHAABAAAAAAA8AAMAAQAAABwABAAgAAAABAAEAAEAAABB//8AAABB////wgABAAAAAAAAAQYAAAEAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhAnkAAAAqACoAKgBGAAAAAgAhAAABKgKaAAMABwAusQEALzyyBwQA7TKxBgXcPLIDAgDtMgCxAwAvPLIFBADtMrIHBgH8PLIBAgDtMjMRIREnMxEjIQEJ6MfHApr9ZiECWAAAAwBk/5wFeAK8AAMABwALAAABNSEVATUhFQE1IRUB9AH0/UQDhPu0BRQB9MjI/tTIyP7UyMgAAAAAAA4ArgABAAAAAAAAACYATgABAAAAAAABAAUAgQABAAAAAAACAAYAlQABAAAAAAADACEA4AABAAAAAAAEAAUBDgABAAAAAAAFABABNgABAAAAAAAGAAUBUwADAAEECQAAAEwAAAADAAEECQABAAoAdQADAAEECQACAAwAhwADAAEECQADAEIAnAADAAEECQAEAAoBAgADAAEECQAFACABFAADAAEECQAGAAoBRwBDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADAAOAAgAE0AbwB6AGkAbABsAGEAIABDAG8AcgBwAG8AcgBhAHQAaQBvAG4AAENvcHlyaWdodCAoYykgMjAwOCBNb3ppbGxhIENvcnBvcmF0aW9uAABNAGEAcgBrAEEAAE1hcmtBAABNAGUAZABpAHUAbQAATWVkaXVtAABGAG8AbgB0AEYAbwByAGcAZQAgADIALgAwACAAOgAgAE0AYQByAGsAQQAgADoAIAA1AC0AMQAxAC0AMgAwADAAOAAARm9udEZvcmdlIDIuMCA6IE1hcmtBIDogNS0xMS0yMDA4AABNAGEAcgBrAEEAAE1hcmtBAABWAGUAcgBzAGkAbwBuACAAMAAwADEALgAwADAAMAAgAABWZXJzaW9uIDAwMS4wMDAgAABNAGEAcgBrAEEAAE1hcmtBAAAAAgAAAAAAAP+DADIAAAABAAAAAAAAAAAAAAAAAAAAAAAEAAAAAQACACQAAAAAAAH//wACAAAAAQAAAADEPovuAAAAAMU4Lm0AAAAAxTgubQ==);
+ }
+ </style>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", false);
+SimpleTest.registerCleanupFunction(() => {
+ SpecialPowers.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+});
+
+function imgListener(img) {
+ return new Promise((resolve, reject) => {
+ img.addEventListener("load", () => resolve());
+ img.addEventListener("error", () => reject());
+ });
+}
+
+function runTests()
+{
+ var iframe = document.getElementById("iframe");
+ iframe.src="data:text/html,hello";
+ let p1 = new Promise((resolve, reject) => {
+ iframe.onload = function() {
+ ok(SpecialPowers.wrap(iframe).contentDocument.nodePrincipal.isNullPrincipal,
+ "iframe should have NullPrincipal.");
+ resolve();
+ }
+ });
+
+ var iframe1 = document.getElementById("iframe1");
+ iframe1.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";
+ let p2 = new Promise((resolve, reject) => {
+ iframe1.onload = function() {
+ ok(SpecialPowers.wrap(iframe1).contentDocument.nodePrincipal.isNullPrincipal,
+ "iframe1 should have NullPrincipal.");
+ resolve();
+ }
+ });
+
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillRect(0, 0, canvas.height, canvas.width);
+ ctx.fillStyle = '#000';
+ var data = canvas.toDataURL('image/png');
+ var img = new Image();
+ img.src = data;
+ let p3 = imgListener(img).then(() => {
+ dump("img onload\n");
+ ctx.drawImage(img, 0, 0);
+ return new Promise((resolve, reject) => {
+ try {
+ ctx.getImageData(0, 0, 1, 1);
+ ok(true, "data:image should be same origin.");
+ resolve();
+ } catch (e) {
+ ok(false, "data:image is cross-origin.");
+ reject();
+ }});
+ }).then(() => {
+ ctx.clearRect(0, 0, canvas.height, canvas.width);
+ ctx.drawImage(document.getElementById('img'), 0, 0);
+ return new Promise((resolve, reject) => {
+ try {
+ canvas.toDataURL();
+ ok(true, "data:image should be same origin.");
+ resolve();
+ } catch (e) {
+ ok(false, "data:image is cross-origin.");
+ reject();
+ }});
+ }).then(() => {
+ var win = window.open("data:text/html,<script>parent.opener.postMessage('ok', '*');<\/script>");
+ return new Promise(resolve => {
+ window.onmessage = function (evt) {
+ is(evt.origin, "null", "The origin of data:text/html should be null.");
+ win.close();
+ resolve();
+ }});
+ });
+
+ var obj_doc = document.getElementById("obj_doc");
+ obj_doc.data="data:text/html,%3Cbody%3E%3Cbutton%3EChild%3C/button%3E%3C/body%3E"
+ let p4 = new Promise((resolve, reject) => {
+ obj_doc.onload = function() {
+ ok(SpecialPowers.wrap(obj_doc).contentDocument.nodePrincipal.isNullPrincipal,
+ "obj_doc.document should have NullPrincipal.");
+ resolve();
+ }
+ });
+
+ var obj_svg = document.getElementById("obj_svg");
+ obj_svg.data='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 200 200"><circle cx="100" cy="100" r="100" fill="green" fill-opacity="0.8"/></svg>'
+ let p5 = new Promise((resolve, reject) => {
+ obj_svg.onload = function() {
+ ok(SpecialPowers.wrap(obj_svg).contentDocument.nodePrincipal.isNullPrincipal,
+ "obj_svg.contentDocument should have NullPrincipal.");
+ ok(SpecialPowers.wrap(obj_svg).getSVGDocument().nodePrincipal.isNullPrincipal,
+ "obj_svg.getSVGDocument() should have NullPrincipal.");
+ resolve();
+ }
+ });
+
+ // Test if data:stylesheet is considered same origin.
+ let p6 = new Promise((resolve, reject) => {
+ // 1. Dynamically include a css by inserting a <link> tag.
+ let link = document.createElement('link');
+ link.rel = 'stylesheet';
+ link.href = "data:text/css,.green-text{color:rgb(0, 255, 0)}";
+ link.onload = function() {
+ let dataStyleSheet;
+ for (let i = 0; i < document.styleSheets.length; i++) {
+ let sheet = document.styleSheets[i];
+ if (sheet.href === link.href) {
+ dataStyleSheet = sheet;
+ break;
+ }
+ }
+ ok(dataStyleSheet, "Should have found data:stylesheet");
+
+ // 2. Try to access the rule. If data:stylesheet is not considered
+ // same origin, an exception will be thrown.
+ try {
+ let rule = dataStyleSheet.cssRules;
+ ok(true, "data:stylesheet is considered same origin.");
+ } catch (ex) {
+ ok(false, "data:stylesheet is NOT considered same origin: " + ex);
+ }
+
+ resolve();
+ };
+ document.head.appendChild(link);
+ });
+
+ // Test if data:font is same-origin.
+ let p7 = new Promise((resolve, reject) => {
+ let text = document.createElement('p');
+ // Cross-domain font will not load according to [1] so we try to apply
+ // data:font to this text and see if the font can be loaded.
+ // [1] https://www.w3.org/TR/css-fonts-3/#same-origin-restriction
+ text.style = 'font-family: DataFont';
+ text.innerHTML = "This text should trigger 'TestFont' to load.";
+ document.body.appendChild(text);
+
+ document.fonts.ready.then(fontFaces => {
+ is(fontFaces.size, 1, "should FontFace entry for data:font");
+ fontFaces.forEach(fontFace => {
+ is(fontFace.status, "loaded", "data:font should be same-origin");
+ });
+ resolve();
+ },
+ _ => {
+ ok(false, "data:font is not same-origin.");
+ reject();
+ });
+ });
+
+ Promise.all([p1, p2, p3, p4, p5, p6, p7]).then(() => {
+ SimpleTest.finish();
+ }).catch((e) => {
+ ok(false, "throwing " + e);
+ SimpleTest.finish();
+ });
+}
+</script>
+
+<body onload="runTests()">
+<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="img">
+<iframe id="iframe"></iframe>
+<iframe id="iframe1" ></iframe>
+<canvas id="canvas" class="output" width="100" height="50"></canvas>
+
+<object id="obj_doc"></object>
+<object id="obj_svg"></object>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/test_delazification_strategy.html b/dom/base/test/test_delazification_strategy.html
new file mode 100644
index 0000000000..ed75182cf0
--- /dev/null
+++ b/dom/base/test/test_delazification_strategy.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1753709 -->
+<!-- Script delazification strategy is not supposed to have any observable
+ side-effect. To make it observable, the ScriptLoader is instrumented to
+ trigger events on the script tag. These events are used to validate that
+ the strategy is used as execpected. This does not garantee that all
+ functions are delazified properly, but this should be checked in the JS
+ engine test suite.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering eager delazification.</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script type="application/javascript">
+ async function WaitForScriptTagEvent() {
+ var url = "file_delazification_strategy.html";
+ var iframe = document.createElement("iframe");
+
+ // Call the resolve function when the event is one of the expected events.
+ // This is made to be used by a promise and provided to event listeners.
+ function resolve_with_event(resolve, evt) {
+ // If we have multiple script tags in the loaded source, make sure
+ // we only watch a single one.
+ if (evt.target.id != "watchme")
+ return;
+
+ switch (evt.type) {
+ case "delazification_on_demand_only":
+ case "delazification_concurrent_depth_first":
+ case "delazification_parse_everything_eagerly":
+ resolve(evt.type.split('_').slice(1).join('_'));
+ break;
+ case "scriptloader_main_thread_compile":
+ resolve(evt.type);
+ break;
+ }
+ return;
+ }
+
+ // Create an event listener, which resolves a promise.
+ let log_event;
+ let scriptLoaderTrace = new Promise((resolve, reject) => {
+ log_event = resolve_with_event.bind(this, resolve);
+ });
+
+ // Wait until the iframe is fully loaded.
+ await new Promise(resolve => {
+ iframe.onload = resolve;
+ iframe.src = url;
+ document.body.appendChild(iframe);
+ });
+
+ // Register all events.
+ let events = [
+ "delazification_on_demand_only",
+ "delazification_concurrent_depth_first",
+ "delazification_parse_everything_eagerly",
+ "scriptloader_main_thread_compile"
+ ];
+ let iwin = iframe.contentWindow;
+ for (let evt of events) {
+ iwin.addEventListener(evt, log_event);
+ }
+
+ // Add a script tag, which will trigger one of the previous events.
+ let script = document.createElement("script");
+ script.setAttribute("id", "watchme");
+ script.setAttribute("src", "file_delazification_strategy.js");
+ iframe.contentDocument.body.appendChild(script);
+
+ // Wait for the event emitted by ScriptLoader, while processing the
+ // previous script.
+ let result = await scriptLoaderTrace;
+
+ // Remove the events and the iframe.
+ for (let evt of events) {
+ iwin.removeEventListener(evt, log_event);
+ }
+ document.body.removeChild(iframe);
+ return result;
+ }
+
+ // Setting dom.expose_test_interfaces pref causes the
+ // nsScriptLoadRequest to fire event on script tags, with information
+ // about its internal state. The ScriptLoader source send events to
+ // trace these and resolve a promise with the path taken by the
+ // script loader.
+ //
+ // Setting dom.script_loader.bytecode_cache.enabled to false in order
+ // to prevent the bytecode cache to perturb this test case.
+ //
+ // Setting dom.script_loader.external_scripts.speculate_* are used to
+ // force off-main-thread compilation, while hoping that we have enough
+ // processors to run the test case
+ //
+ // Setting dom.delazification.* are used to select the delazification
+ // strategy and to check that it is well selected.
+ promise_test(async function() {
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.enabled', false],
+ ['dom.script_loader.external_scripts.speculate_non_parser_inserted.enable', true],
+ ['dom.script_loader.external_scripts.speculate_async.enabled', true],
+ ['dom.script_loader.external_scripts.speculate_link_preload.enabled', true],
+ // Parse everything eagerly
+ ['dom.script_loader.delazification.strategy', 255],
+ ['dom.script_loader.delazification.max_size', 0],
+ ['dom.script_loader.delazification.min_mem', 0],
+ ]});
+
+ assert_equals(await WaitForScriptTagEvent(), "on_demand_only",
+ "[1] AttemptAsyncScriptCompile: On demand only");
+ }, "Check that max_size can disable delazification strategy");
+
+ promise_test(async function() {
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.enabled', false],
+ // Enable OffMainThread compilation for everything, and cross-fingers
+ // about the number of CPU.
+ ['dom.script_loader.external_scripts.speculate_non_parser_inserted.enable', true],
+ ['dom.script_loader.external_scripts.speculate_async.enabled', true],
+ ['dom.script_loader.external_scripts.speculate_link_preload.enabled', true],
+ // Parse everything eagerly
+ ['dom.script_loader.delazification.strategy', 255],
+ ['dom.script_loader.delazification.max_size', 10485760],
+ // 4 TB should of RAM be enough.
+ ['dom.script_loader.delazification.min_mem', 4096],
+ ]});
+
+ assert_equals(await WaitForScriptTagEvent(), "on_demand_only",
+ "[2] AttemptAsyncScriptCompile: On demand only");
+ }, "Check that min_mem can disable delazification strategy");
+
+ promise_test(async function() {
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.enabled', false],
+ // Enable OffMainThread compilation for everything, and cross-fingers
+ // about the number of CPU.
+ ['dom.script_loader.external_scripts.speculate_non_parser_inserted.enable', true],
+ ['dom.script_loader.external_scripts.speculate_async.enabled', true],
+ ['dom.script_loader.external_scripts.speculate_link_preload.enabled', true],
+ ['dom.script_loader.delazification.max_size', 10485760],
+ ['dom.script_loader.delazification.min_mem', 0],
+ ]});
+
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.delazification.strategy', 0],
+ ]});
+ assert_equals(await WaitForScriptTagEvent(), "on_demand_only",
+ "[3] AttemptAsyncScriptCompile: On demand only");
+
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.delazification.strategy', 2],
+ ]});
+ assert_equals(await WaitForScriptTagEvent(), "concurrent_depth_first",
+ "[3] AttemptAsyncScriptCompile: Concurrent Depth First");
+
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.delazification.strategy', 255],
+ ]});
+ assert_equals(await WaitForScriptTagEvent(), "parse_everything_eagerly",
+ "[3] AttemptAsyncScriptCompile: Parse Everything Eagerly");
+ }, "Check enabling delazification strategy works");
+
+ done();
+ </script>
+</head>
+<body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1753709">Mozilla Bug 1753709</a>
+</body>
+</html>
diff --git a/dom/base/test/test_document.all_iteration.html b/dom/base/test/test_document.all_iteration.html
new file mode 100644
index 0000000000..a5140d9df1
--- /dev/null
+++ b/dom/base/test/test_document.all_iteration.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for document.all iteration behavior</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_array_equals([...document.all], document.getElementsByTagName("*"));
+}, "document.all should be iterable");
+</script>
diff --git a/dom/base/test/test_document.all_unqualified.html b/dom/base/test/test_document.all_unqualified.html
new file mode 100644
index 0000000000..648ff6bb48
--- /dev/null
+++ b/dom/base/test/test_document.all_unqualified.html
@@ -0,0 +1,35 @@
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 823283</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=823283">Mozilla Bug 823283</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<form id="f" onreset="window.valueOfAll = all; SimpleTest.executeSoon(finishTest); return false;">
+</form>
+</div>
+<pre id="test">
+<script>
+SimpleTest.waitForExplicitFinish();
+
+var all = 17;
+var valueOfAll = "initial value";
+
+function finishTest()
+{
+ is(valueOfAll, document.all,
+ "wrong value for |all| in event handler attribute; note that the wrong " +
+ "value may be |document.forms.f.all| in browsers with an 'all' property " +
+ "on elements");
+ SimpleTest.finish();
+}
+
+window.addEventListener("load", function() { document.getElementById("f").reset(); });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_document_constructor.html b/dom/base/test/test_document_constructor.html
new file mode 100644
index 0000000000..f57a525eda
--- /dev/null
+++ b/dom/base/test/test_document_constructor.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1017932
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1017932</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 1017932 **/
+ var doc = new Document;
+ ok(doc instanceof Document, "Should have a document");
+ ok(!(doc instanceof XMLDocument), "Should not be an XMLDocument");
+ ok(!("load" in doc), "Should not have a load() method");
+ is(Object.getPrototypeOf(doc), Document.prototype,
+ "Should have the right proto");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1017932">Mozilla Bug 1017932</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_document_importNode_document.html b/dom/base/test/test_document_importNode_document.html
new file mode 100644
index 0000000000..73afabe1bf
--- /dev/null
+++ b/dom/base/test/test_document_importNode_document.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1177914
+-->
+<head>
+ <title>Test for Bug 1177914</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=1177914">Mozilla Bug 1177914</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var thrownException = false;
+
+try {
+ document.importNode(document);
+} catch(err) {
+ thrownException = err;
+}
+
+ok(thrownException !== false, "An exception should've been thrown");
+is(thrownException.name, "NotSupportedError", "A NotSupportedError exception should've been thrown");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_document_wireframe.html b/dom/base/test/test_document_wireframe.html
new file mode 100644
index 0000000000..ddb6ea888d
--- /dev/null
+++ b/dom/base/test/test_document_wireframe.html
@@ -0,0 +1,354 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Tests for document.getWireframe()</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ /**
+ * This test creates some simple webpages, captures wireframes for them, and
+ * then compares them against some expected wireframe structures.
+ */
+
+ /**
+ * Converts some RGB values into the same uint32_t nsColor representation
+ * that getWireframe uses.
+ *
+ * @param {Number} r
+ * Red color value.
+ * @param {Number} g
+ * Green color value.
+ * @param {Number} b
+ * Blue color value.
+ * @returns {Number}
+ * The red, green and blue values composed in a single uint32_t-compatible
+ * value.
+ */
+ function nscolor(r, g, b) {
+ return (255 << 24 | b << 16 | g << 8 | r) >>> 0;
+ }
+
+ const WHITE_NSCOLOR = nscolor(255, 255, 255);
+
+ const RED_RGB = "rgb(255, 0, 0)";
+ const RED_NSCOLOR = nscolor(255, 0, 0);
+ const GREEN_RGB = "rgb(0, 255, 0)";
+ const GREEN_NSCOLOR = nscolor(0, 255, 0);
+ const BLUE_RGB = "rgb(0, 0, 255)";
+ const BLUE_NSCOLOR = nscolor(0, 0, 255);
+ const BLACK_RGB = "rgb(0, 0, 0)";
+ const BLACK_NSCOLOR = nscolor(0, 0, 0);
+ const BUILDER = "http://mochi.test:8888/document-builder.sjs?html=";
+ const TEST_PATH = "http://mochi.test:8888/tests/dom/base/test/";
+
+ /**
+ * This array contains the definition of each test. Each test is an object
+ * that expects two properties:
+ *
+ * {String} html
+ * The markup to be loaded in the page iframe that a wireframe will be
+ * generated for.
+ * {Object} expectedWireframe
+ * An approximation of the wireframe that should be generated. The
+ * approximation is due to the fact that different platforms and
+ * execution environments might produce slightly different positioning
+ * of wireframe rects. We skip comparing the position of the rects, and
+ * only look at their dimensions (sometimes only one dimension if the
+ * other is potentially more variable - for example with text). Properties
+ * included in this object will do a strict comparison with the generated
+ * wireframe. Properties in the generated wireframe that are not in the
+ * expectedWireframe will be ignored.
+ */
+ const kTests = [{
+ // Base case: a simple solid background with a single character in the
+ // foreground.
+ html: `
+ <html>
+ <style>
+ body {
+ width: 500px;
+ height: 500px;
+ background-color: ${RED_RGB};
+ color: ${BLACK_RGB};
+ overflow: hidden;
+ font-size: 12px;
+ }
+ </style>
+ <body>x</body>
+ </html>
+ `,
+ expectedWireframe: {
+ canvasBackground: RED_NSCOLOR,
+ rects: [{
+ color: BLACK_NSCOLOR,
+ height: 12,
+ type: "text",
+ }]
+ },
+ }, {
+ // Additional background on top of the main background.
+ html: `
+ <html>
+ <style>
+ body {
+ background-color: ${RED_RGB};
+ color: ${BLACK_RGB};
+ overflow: hidden;
+ font-size: 12px;
+ }
+ div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 20px;
+ height: 20px;
+ background-color: ${GREEN_RGB};
+ }
+ </style>
+ <body>
+ <div>x</div>
+ </body>
+ </html>
+ `,
+ expectedWireframe: {
+ canvasBackground: RED_NSCOLOR,
+ rects: [{
+ color: GREEN_NSCOLOR,
+ height: 20,
+ width: 20,
+ type: "background",
+ }, {
+ color: BLACK_NSCOLOR,
+ height: 12,
+ type: "text",
+ }]
+ },
+ }, {
+ // Image on top of the main background with another background
+ // floating in the top right.
+ html: `
+ <html>
+ <style>
+ body {
+ background-color: ${RED_RGB};
+ color: ${BLACK_RGB};
+ overflow: hidden;
+ font-size: 12px;
+ }
+ div {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 20px;
+ height: 20px;
+ background-color: ${GREEN_RGB};
+ }
+ img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 50px;
+ width: 50px;
+ }
+ </style>
+ <body>
+ <img src="${TEST_PATH}/green.png"/>
+ <div>x</div>
+ </body>
+ </html>
+ `,
+ expectedWireframe: {
+ canvasBackground: RED_NSCOLOR,
+ rects: [{
+ color: 0,
+ height: 50,
+ width: 50,
+ type: "image",
+ }, {
+ color: GREEN_NSCOLOR,
+ height: 20,
+ width: 20,
+ type: "background",
+ }, {
+ color: BLACK_NSCOLOR,
+ height: 12,
+ type: "text",
+ }]
+ },
+ }, {
+ // Image on top of the main background with another background
+ // floating over the image
+ html: `
+ <html>
+ <style>
+ body {
+ width: 500px;
+ height: 500px;
+ background-color: ${RED_RGB};
+ color: ${BLACK_RGB};
+ overflow: hidden;
+ font-size: 12px;
+ }
+ div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 20px;
+ height: 20px;
+ background-color: ${BLUE_RGB};
+ }
+ img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 50px;
+ width: 50px;
+ }
+ </style>
+ <body>
+ <img src="${TEST_PATH}/green.png"/>
+ <div>x</div>
+ </body>
+ </html>
+ `,
+ expectedWireframe: {
+ canvasBackground: RED_NSCOLOR,
+ rects: [{
+ color: 0,
+ height: 50,
+ width: 50,
+ type: "image",
+ }, {
+ color: BLUE_NSCOLOR,
+ height: 20,
+ width: 20,
+ type: "background",
+ }, {
+ color: BLACK_NSCOLOR,
+ height: 12,
+ type: "text",
+ }]
+ },
+ }, {
+ // Bug 1759919 - Transformed items incorrectly causing us to not keep hit
+ // testing stuff.
+ html: `
+ <!doctype html>
+ <style>:root { background-color: white; } body { margin: 0 }</style>
+ <div style="transform: rotate(90deg); width: 20px; height: 20px; overflow: clip;">
+ <div style="width: 100%; height: 100%; background-color: blue;"></div>
+ </div>
+ <div style="transform: rotate(90deg); width: 20px; height: 20px; overflow: clip;">
+ <div style="width: 100%; height: 100%; background-color: red;"></div>
+ </div>
+ `,
+ expectedWireframe: {
+ canvasBackground: WHITE_NSCOLOR,
+ rects: [{
+ color: RED_NSCOLOR,
+ height: 20,
+ width: 20,
+ x: 0,
+ y: 0,
+ type: "background",
+ }, {
+ color: BLUE_NSCOLOR,
+ height: 20,
+ width: 20,
+ x: 0,
+ y: 20,
+ type: "background",
+ }],
+ }
+ }];
+
+ /**
+ * Returns a Promise once page has been loaded in frame.
+ *
+ * @param {Element} frame
+ * The iframe to load the page in.
+ * @param {String} page
+ * The URL of the page to load in the frame.
+ * @returns Promise
+ * @resolves undefined
+ * Once the load event has fired for the frame.
+ */
+ function loadInIframe(frame, page) {
+ return new Promise(resolve => {
+ frame.addEventListener("load", resolve, { once: true });
+ frame.src = page;
+ });
+ }
+
+ /**
+ * Compares a generated wireframe to an Object that contains some or all of
+ * the expected structure of the generated wireframe.
+ *
+ * If the wireframe doesn't contain the expected number of rects, the
+ * serialized structure of both the wireframe and approximateWireframe will
+ * be dumped to stdout.
+ *
+ * @param {Wireframe} wireframe
+ * A wireframe generated via document.getWireframe()
+ * @param {Object} approximateWireframe
+ * An object that closely resembles a wireframe but the rects in the
+ * rects property do not need to contain all of the properties expected
+ * in a WireframeTaggedRect. Skipped properties won't be checked.
+ */
+ function assertApproximateWireframe(wireframe, approximateWireframe) {
+ is(
+ wireframe.canvasBackground,
+ approximateWireframe.canvasBackground,
+ "Canvas backgrounds match."
+ );
+ is(
+ wireframe.rects.length,
+ approximateWireframe.rects.length,
+ "Same rect count"
+ );
+ if (wireframe.rects.length != approximateWireframe.rects.length) {
+ dump(
+ "Generated wireframe: " + JSON.stringify(wireframe, null, "\t") + "\n"
+ );
+ dump(
+ "Expected approximate wireframe: " +
+ JSON.stringify(approximateWireframe, null, "\t") +
+ "\n"
+ );
+ }
+
+ for (let index = 0; index < approximateWireframe.length; ++index) {
+ let wireframeRect = wireframe.rects[index];
+ let approximationRect = approximateWireframe.rects[index];
+ for (let prop of approximationRect) {
+ is(
+ wireframeRect[prop],
+ approximationRect[prop],
+ `Property ${prop} should be equal.`
+ );
+ }
+ }
+ }
+
+ add_task(async () => {
+ const iframe = document.getElementById("iframe");
+
+ for (let testDefinition of kTests) {
+ let pageURL = BUILDER + encodeURIComponent(testDefinition.html);
+ await loadInIframe(iframe, pageURL);
+ let wireframe = SpecialPowers.wrap(
+ iframe.contentDocument
+ ).getWireframe();
+ assertApproximateWireframe(wireframe, testDefinition.expectedWireframe);
+ }
+ });
+ </script>
+</head>
+<body>
+<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/base/test/test_domparser_null_char.html b/dom/base/test/test_domparser_null_char.html
new file mode 100644
index 0000000000..af35d89ec8
--- /dev/null
+++ b/dom/base/test/test_domparser_null_char.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=817469
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 817469</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=817469">Mozilla Bug 817469</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 817469 **/
+ var doc = new DOMParser().parseFromString("\x00<div id='myElement'>", "text/html");
+ isnot(doc.getElementById("myElement"), null, "Should not stop at null");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_domparsing.html b/dom/base/test/test_domparsing.html
new file mode 100644
index 0000000000..371fb1d178
--- /dev/null
+++ b/dom/base/test/test_domparsing.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset=utf-8>
+ <title>Test for the DOM Parsing and Serialization Standard</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=816410">Mozilla Bug 816410</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+"use strict";
+/** Test for Bug 816410 **/
+
+function throws(fn, type, message) {
+ try {
+ fn();
+ ok(false, message);
+ } catch (e) {
+ if (type) {
+ is(e.name, type, message);
+ } else {
+ ok(true, message);
+ }
+ }
+}
+
+let parser = new DOMParser();
+is(typeof parser.parseFromString, "function", "parseFromString should exist");
+is(typeof parser.parseFromBuffer, "undefined", "parseFromBuffer should NOT be visible from unprivileged callers");
+is(typeof parser.parseFromStream, "undefined", "parseFromStream should NOT be visible from unprivileged callers");
+is(typeof parser.init, "undefined", "init should NOT be visible from unprivileged callers");
+
+// The three-arguments constructor should not be visible from
+// unprivileged callers for interoperability with other browsers.
+// But we have no way to do that right now.
+try {
+ new DOMParser(undefined);
+ new DOMParser(null);
+ new DOMParser(false);
+ new DOMParser(0);
+ new DOMParser("");
+ new DOMParser({});
+} catch (e) {
+ todo(false, "DOMParser constructor should not throw for extra arguments");
+}
+
+let serializer = new XMLSerializer();
+is(typeof serializer.serializeToString, "function", "serializeToString should exist");
+is(typeof serializer.serializeToStream, "undefined", "serializeToStream should NOT be visible from unprivileged callers");
+
+// XMLSerializer constructor should not throw for extra arguments
+new XMLSerializer(undefined);
+new XMLSerializer(null);
+new XMLSerializer(false);
+new XMLSerializer(0);
+new XMLSerializer("");
+new XMLSerializer({});
+
+let tests = [
+ {input: "<html></html>", type: "text/html",
+ expected: '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body></body></html>'},
+ {input: "<xml></xml>", type: "text/xml", expected: "<xml/>"},
+ {input: "<xml></xml>", type: "application/xml", expected: "<xml/>"},
+ {input: "<html></html>", type: "application/xhtml+xml", expected: "<html/>"},
+ {input: "<svg></svg>", type: "image/svg+xml", expected: "<svg/>"},
+];
+for (let t of tests) {
+ is(serializer.serializeToString(parser.parseFromString(t.input, t.type)), t.expected,
+ "parseFromString test for " + t.type);
+}
+
+throws(function() {
+ parser.parseFromString("<xml></xml>", "foo/bar");
+}, "TypeError", "parseFromString should throw for the unknown type");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_domrequest.html b/dom/base/test/test_domrequest.html
new file mode 100644
index 0000000000..1aea26f657
--- /dev/null
+++ b/dom/base/test/test_domrequest.html
@@ -0,0 +1,233 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for DOMRequest</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 class="testbody" type="application/javascript">
+"use strict";
+
+var reqserv = SpecialPowers.getDOMRequestService();
+ok("createRequest" in reqserv, "appears to be a service");
+
+function testBasics() {
+ // create a request
+ var req = reqserv.createRequest(window);
+ ok("result" in req, "request has result");
+ ok("error" in req, "request has error");
+ ok("onsuccess" in req, "request has onsuccess");
+ ok("onerror" in req, "request has onerror");
+ ok("readyState" in req, "request has readyState");
+ ok("then" in req, "request has then");
+
+ is(req.readyState, "pending", "readyState is pending");
+ is(req.result, undefined, "result is undefined");
+ is(req.onsuccess, null, "onsuccess is null");
+ is(req.onerror, null, "onerror is null");
+
+ runTest();
+}
+
+function testSuccess() {
+ // fire success
+ var req = reqserv.createRequest(window);
+ var ev = null;
+ req.onsuccess = function(e) {
+ ev = e;
+ }
+ var result = null;
+ var promise = req.then(function(r) {
+ is(r, "my result", "correct result when resolving the promise");
+ result = r;
+ runTest();
+ }, function(e) {
+ ok(false, "promise should not be rejected");
+ runTest();
+ });
+ ok(promise instanceof Promise, "then() should return a Promise");
+ reqserv.fireSuccess(req, "my result");
+ ok(ev, "got success event");
+ is(ev.type, "success", "correct type during success");
+ is(ev.target, req, "correct target during success");
+ is(req.readyState, "done", "correct readyState after success");
+ is(req.error, null, "correct error after success");
+ is(req.result, "my result", "correct result after success");
+ is(result, null, "Promise should not be resolved synchronously");
+}
+
+function testError() {
+ // fire error
+ var req = reqserv.createRequest(window);
+ var ev = null;
+ req.onerror = function(e) {
+ ev = e;
+ }
+ var error = null;
+ var promise = req.then(function(r) {
+ ok(false, "promise should not be resolved");
+ runTest();
+ }, function(e) {
+ ok(e instanceof DOMException, "got error rejection");
+ ok(e === req.error, "got correct error when rejecting the promise");
+ error = e;
+ runTest();
+ });
+ ok(promise instanceof Promise, "then() should return a Promise");
+ reqserv.fireError(req, "OhMyError");
+ ok(ev, "got error event");
+ is(ev.type, "error", "correct type during error");
+ is(ev.target, req, "correct target during error");
+ is(req.readyState, "done", "correct readyState after error");
+ is(req.error.name, "UnknownError", "correct error type after error");
+ is(req.error.message, "OhMyError", "correct error message after error");
+ is(req.result, undefined, "correct result after error");
+ is(error, null, "Promise should not be rejected synchronously");
+}
+
+function testDetailedError() {
+ // fire detailed error
+ var req = reqserv.createRequest(window);
+ var ev = null;
+ req.onerror = function(e) {
+ ev = e;
+ };
+ var error = null;
+ var promise = req.then(function(r) {
+ ok(false, "promise should not be resolved");
+ runTest();
+ }, function(e) {
+ ok(e instanceof DOMException, "got error rejection");
+ ok(e === req.error, "got correct error when rejecting the promise");
+ error = e;
+ runTest();
+ });
+ ok(promise instanceof Promise, "then() should return a Promise");
+ SpecialPowers.wrwp(req).fireDetailedError(new DOMException("detailedError"));
+ ok(ev, "got error event");
+ is(ev.type, "error", "correct type during error");
+ is(ev.target, req, "correct target during error");
+ is(req.readyState, "done", "correct readyState after error");
+ is(req.error.name, "UnknownError", "correct error type after error");
+ is(req.error.message, "detailedError", "correct error message after error");
+ is(req.result, undefined, "correct result after error");
+ is(error, null, "Promise should not be rejected synchronously");
+}
+
+function testThenAfterSuccess() {
+ // fire success
+ var req = reqserv.createRequest(window);
+ var ev = null;
+ req.onsuccess = function(e) {
+ ev = e;
+ }
+ reqserv.fireSuccess(req, "my result");
+ ok(ev, "got success event");
+ is(ev.type, "success", "correct type during success");
+ is(ev.target, req, "correct target during success");
+ is(req.readyState, "done", "correct readyState after success");
+ is(req.error, null, "correct error after success");
+ is(req.result, "my result", "correct result after success");
+ var result = null;
+ var promise = req.then(function(r) {
+ is(r, "my result", "correct result when resolving the promise");
+ result = r;
+ runTest();
+ }, function(e) {
+ ok(false, "promise should not be rejected");
+ runTest();
+ });
+ ok(promise instanceof Promise, "then() should return a Promise");
+ is(result, null, "Promise should not be resolved synchronously");
+}
+
+function testThenAfterError() {
+ // fire error
+ var req = reqserv.createRequest(window);
+ var ev = null;
+ req.onerror = function(e) {
+ ev = e;
+ }
+ reqserv.fireError(req, "OhMyError");
+ ok(ev, "got error event");
+ is(ev.type, "error", "correct type during error");
+ is(ev.target, req, "correct target during error");
+ is(req.readyState, "done", "correct readyState after error");
+ is(req.error.name, "UnknownError", "correct error type after error");
+ is(req.error.message, "OhMyError", "correct error message after error");
+ is(req.result, undefined, "correct result after error");
+ var error = null;
+ var promise = req.then(function(r) {
+ ok(false, "promise should not be resolved");
+ runTest();
+ }, function(e) {
+ ok(e instanceof DOMException, "got error rejection");
+ ok(e === req.error, "got correct error when rejecting the promise");
+ error = e;
+ runTest();
+ });
+ ok(promise instanceof Promise, "then() should return a Promise");
+ is(error, null, "Promise should not be rejected synchronously");
+}
+
+function testDetailedError() {
+ // fire detailed error
+ var req = reqserv.createRequest(window);
+ var ev = null;
+ req.onerror = function(e) {
+ ev = e;
+ };
+ var error = null;
+ var promise = req.then(function(r) {
+ ok(false, "promise should not be resolved");
+ runTest();
+ }, function(e) {
+ ok(e instanceof DOMException, "got error rejection");
+ ok(e === req.error, "got correct error when rejecting the promise");
+ error = e;
+ runTest();
+ });
+ ok(promise instanceof Promise, "then() should return a Promise");
+ SpecialPowers.wrap(req).fireDetailedError(new DOMException("detailedError"));
+ ok(ev, "got error event");
+ is(ev.type, "error", "correct type during error");
+ is(ev.target, req, "correct target during error");
+ is(req.readyState, "done", "correct readyState after error");
+ is(req.error.name, "Error", "correct error type after error");
+ is(req.error.message, "detailedError", "correct error message after error");
+ is(req.result, undefined, "correct result after error");
+ is(error, null, "Promise should not be rejected synchronously");
+}
+
+var tests = [
+ testBasics,
+ testSuccess,
+ testError,
+ testDetailedError,
+ testThenAfterSuccess,
+ testThenAfterError,
+];
+
+function runTest() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+runTest();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_domrequesthelper.xhtml b/dom/base/test/test_domrequesthelper.xhtml
new file mode 100644
index 0000000000..e5f3d8f0f1
--- /dev/null
+++ b/dom/base/test/test_domrequesthelper.xhtml
@@ -0,0 +1,547 @@
+<?xml version="1.0"?>
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="DOMRequestHelper Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="start();">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <script type="application/javascript">
+ <![CDATA[
+ const {DOMRequestIpcHelper} = ChromeUtils.import("resource://gre/modules/DOMRequestHelper.jsm");
+ let obs = Cc["@mozilla.org/observer-service;1"].
+ getService(Ci.nsIObserverService);
+ let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService();
+
+ function DummyHelperSubclass() {
+ this.onuninit = null;
+ }
+ DummyHelperSubclass.prototype = {
+ __proto__: DOMRequestIpcHelper.prototype,
+ uninit: function() {
+ if (typeof this.onuninit === "function") {
+ this.onuninit();
+ }
+ this.onuninit = null;
+ }
+ };
+
+ var dummy = new DummyHelperSubclass();
+ var isDOMRequestHelperDestroyed = false;
+
+ /**
+ * Init & destroy.
+ */
+ function initDOMRequestHelperTest(aMessages) {
+ // If we haven't initialized the DOMRequestHelper object, its private
+ // properties will be undefined, but once destroyDOMRequestHelper is
+ // called, they're set to null.
+ var expectedPrivatePropertyValues =
+ isDOMRequestHelperDestroyed ? null : undefined;
+
+ is(dummy._requests, expectedPrivatePropertyValues, "Request is expected");
+ is(dummy._messages, undefined, "Messages is undefined");
+ is(dummy._window, expectedPrivatePropertyValues, "Window is expected");
+
+ dummy.initDOMRequestHelper(window, aMessages);
+
+ ok(dummy._window, "Window exists");
+ is(dummy._window, window, "Correct window");
+ if (aMessages) {
+ is(typeof dummy._listeners, "object", "Listeners is an object");
+ }
+ }
+
+ function destroyDOMRequestHelperTest() {
+ dummy.destroyDOMRequestHelper();
+ isDOMRequestHelperDestroyed = true;
+
+ is(dummy._requests, null, "Request is null");
+ is(dummy._messages, undefined, "Messages is undefined");
+ is(dummy._window, null, "Window is null");
+ }
+
+ /**
+ * Message listeners.
+ */
+ function checkMessageListeners(aExpectedListeners, aCount) {
+ info("Checking message listeners\n" + "Expected listeners " +
+ JSON.stringify(aExpectedListeners) + " \nExpected count " + aCount);
+ let count = 0;
+ Object.keys(dummy._listeners).forEach(function(name) {
+ count++;
+ is(aExpectedListeners[name].weakRef, dummy._listeners[name].weakRef,
+ "Message found " + name + " - Same weakRef");
+ is(aExpectedListeners[name].count, dummy._listeners[name].count,
+ "Message found " + name + " - Same count");
+ });
+ is(aCount, count, "Correct number of listeners");
+ }
+
+ function addMessageListenersTest(aMessages, aExpectedListeners, aCount) {
+ dummy.addMessageListeners(aMessages);
+ info(JSON.stringify(dummy._listeners));
+ checkMessageListeners(aExpectedListeners, aCount);
+ }
+
+ function removeMessageListenersTest(aMessages, aExpectedListeners, aCount) {
+ dummy.removeMessageListeners(aMessages);
+ checkMessageListeners(aExpectedListeners, aCount);
+ }
+
+ /**
+ * Utility function to test window destruction behavior. In general this
+ * function does the following:
+ *
+ * 1) Create a new iframe
+ * 2) Create a new DOMRequestHelper
+ * 3) initDOMRequestHelper(), optionally with weak or strong listeners
+ * 4) Optionally force a garbage collection to reap weak references
+ * 5) Destroy the iframe triggering an inner-window-destroyed event
+ * 6) Callback with a boolean indicating if DOMRequestHelper.uninit() was
+ * called.
+ *
+ * Example usage:
+ *
+ * checkWindowDestruction({ messages: ["foo"], gc: true },
+ * function(uninitCalled) {
+ * // expect uninitCalled === false since GC with only weak refs
+ * });
+ */
+ const TOPIC = "inner-window-destroyed";
+ function checkWindowDestruction(aOptions, aCallback) {
+ aOptions = aOptions || {};
+ aOptions.messages = aOptions.messages || [];
+ aOptions.gc = !!aOptions.gc;
+
+ if (typeof aCallback !== "function") {
+ aCallback = function() { };
+ }
+
+ let uninitCalled = false;
+
+ // Use a secondary observer so we know when to expect the uninit(). We
+ // can then reasonably expect uninitCalled to be set properly on the
+ // next tick.
+ let observer = {
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic !== TOPIC) {
+ return;
+ }
+ obs.removeObserver(observer, TOPIC);
+ setTimeout(function() {
+ aCallback(uninitCalled);
+ });
+ }
+ };
+
+ let frame = document.createXULElement("iframe");
+ frame.onload = function() {
+ obs.addObserver(observer, TOPIC);
+ // Create dummy DOMRequestHelper specific to checkWindowDestruction()
+ let cwdDummy = new DummyHelperSubclass();
+ cwdDummy.onuninit = function() {
+ uninitCalled = true;
+
+ if (!aOptions.messages || !aOptions.messages.length) {
+ return;
+ }
+
+ // If all message listeners are removed, cwdDummy.receiveMessage
+ // should never be called.
+ ppmm.broadcastAsyncMessage(aOptions.messages[0].name);
+ };
+
+ // Test if we still receive messages from ppmm.
+ cwdDummy.receiveMessage = function(aMessage) {
+ ok(false, "cwdDummy.receiveMessage should NOT be called: " + aMessage.name);
+ };
+
+ cwdDummy.initDOMRequestHelper(frame.contentWindow, aOptions.messages);
+ // Make sure to clear our strong ref here so that we can test our
+ // weak reference listeners and observer.
+ cwdDummy = null;
+ if (aOptions.gc) {
+ Cu.schedulePreciseGC(function() {
+ SpecialPowers.DOMWindowUtils.cycleCollect();
+ SpecialPowers.DOMWindowUtils.garbageCollect();
+ SpecialPowers.DOMWindowUtils.garbageCollect();
+ document.documentElement.removeChild(frame);
+ });
+ return;
+ }
+ document.documentElement.removeChild(frame);
+ };
+ document.documentElement.appendChild(frame);
+ }
+
+ /**
+ * Test steps.
+ */
+ var tests = [
+ function() {
+ info("== InitDOMRequestHelper no messages");
+ initDOMRequestHelperTest(null);
+ next();
+ },
+ function() {
+ info("== DestroyDOMRequestHelper");
+ destroyDOMRequestHelperTest();
+ next();
+ },
+ function() {
+ info("== InitDOMRequestHelper empty array");
+ initDOMRequestHelperTest([]);
+ checkMessageListeners({}, 0);
+ next();
+ },
+ function() {
+ info("== DestroyDOMRequestHelper");
+ destroyDOMRequestHelperTest();
+ next();
+ },
+ function() {
+ info("== InitDOMRequestHelper with strings array");
+ initDOMRequestHelperTest(["name1", "nameN"]);
+ checkMessageListeners({"name1": {weakRef: false, count: 1},
+ "nameN": {weakRef: false, count: 1}}, 2);
+ next();
+ },
+ function() {
+ info("== DestroyDOMRequestHelper");
+ destroyDOMRequestHelperTest();
+ next();
+ },
+ function() {
+ info("== InitDOMRequestHelper with objects array");
+ initDOMRequestHelperTest([{
+ name: "name1",
+ weakRef: false
+ }, {
+ name: "nameN",
+ weakRef: true
+ }]);
+ checkMessageListeners({
+ "name1": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 2);
+ next();
+ },
+ function() {
+ info("== AddMessageListeners empty array");
+ addMessageListenersTest([], {
+ "name1": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 2);
+ next();
+ },
+ function() {
+ info("== AddMessageListeners null");
+ addMessageListenersTest(null, {
+ "name1": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 2);
+ next();
+ },
+ function() {
+ info("== AddMessageListeners new listener, string only");
+ addMessageListenersTest("name2", {
+ "name1": {weakRef: false, count: 1},
+ "name2": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 3);
+ next();
+ },
+ function() {
+ info("== AddMessageListeners new listeners, strings array");
+ addMessageListenersTest(["name3", "name4"], {
+ "name1": {weakRef: false, count: 1},
+ "name2": {weakRef: false, count: 1},
+ "name3": {weakRef: false, count: 1},
+ "name4": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 5);
+ next();
+ },
+ function() {
+ info("== AddMessageListeners new listeners, objects array");
+ addMessageListenersTest([{
+ name: "name5",
+ weakRef: true
+ }, {
+ name: "name6",
+ weakRef: false
+ }], {
+ "name1": {weakRef: false, count: 1},
+ "name2": {weakRef: false, count: 1},
+ "name3": {weakRef: false, count: 1},
+ "name4": {weakRef: false, count: 1},
+ "name5": {weakRef: true, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 7);
+ next();
+ },
+ function() {
+ info("== RemoveMessageListeners, null");
+ removeMessageListenersTest(null, {
+ "name1": {weakRef: false, count: 1},
+ "name2": {weakRef: false, count: 1},
+ "name3": {weakRef: false, count: 1},
+ "name4": {weakRef: false, count: 1},
+ "name5": {weakRef: true, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 7);
+ next();
+ },
+ function() {
+ info("== RemoveMessageListeners, one message");
+ removeMessageListenersTest("name1", {
+ "name2": {weakRef: false, count: 1},
+ "name3": {weakRef: false, count: 1},
+ "name4": {weakRef: false, count: 1},
+ "name5": {weakRef: true, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 6);
+ next();
+ },
+ function() {
+ info("== RemoveMessageListeners, array of messages");
+ removeMessageListenersTest(["name2", "name3"], {
+ "name4": {weakRef: false, count: 1},
+ "name5": {weakRef: true, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 4);
+ next();
+ },
+ function() {
+ info("== RemoveMessageListeners, unknown message");
+ removeMessageListenersTest("unknown", {
+ "name4": {weakRef: false, count: 1},
+ "name5": {weakRef: true, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 4);
+ next();
+ },
+ function() {
+ try {
+ info("== AddMessageListeners, same message, same kind");
+ addMessageListenersTest("name4", {
+ "name4": {weakRef: false, count: 2},
+ "name5": {weakRef: true, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 4);
+ next();
+ } catch (ex) {
+ ok(false, "Unexpected exception " + ex);
+ }
+ },
+ function() {
+ info("== AddMessageListeners, same message, different kind");
+ try {
+ addMessageListenersTest({name: "name4", weakRef: true}, {
+ "name4": {weakRef: false, count: 2},
+ "name5": {weakRef: true, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 4);
+ ok(false, "Should have thrown an exception");
+ } catch (ex) {
+ ok(true, "Expected exception");
+ next();
+ }
+ },
+ function() {
+ info("== RemoveMessageListeners, message with two listeners");
+ try {
+ removeMessageListenersTest(["name4", "name5"], {
+ "name4": {weakRef: false, count: 1},
+ "name6": {weakRef: false, count: 1},
+ "nameN": {weakRef: true, count: 1}
+ }, 3);
+ next();
+ } catch (ex) {
+ ok(false, "Unexpected exception " + ex);
+ }
+ },
+ function() {
+ info("== Test createRequest()");
+ ok(DOMRequest, "DOMRequest object exists");
+ var req = dummy.createRequest();
+ ok(DOMRequest.isInstance(req), "Returned a DOMRequest");
+ next();
+ },
+ function() {
+ info("== Test getRequestId(), removeRequest() and getRequest()");
+ var req = dummy.createRequest();
+ var id = dummy.getRequestId(req);
+ is(typeof id, "string", "id is a string");
+ var req_ = dummy.getRequest(id);
+ is(req, req_, "Got correct request");
+ dummy.removeRequest(id);
+ req = dummy.getRequest(id);
+ is(req, undefined, "No request");
+ next();
+ },
+ function() {
+ info("== Test createPromise()");
+ ok(Promise, "Promise object exists");
+ var promise = dummy.createPromise(function(resolve, reject) {
+ resolve(true);
+ });
+ ok(promise instanceof Promise, "Returned a Promise");
+ promise.then(next);
+ },
+ function() {
+ info("== Test createPromiseWithId()");
+ var _resolverId;
+ var promise = dummy.createPromiseWithId(function(resolverId) {
+ _resolverId = resolverId;
+ });
+ var resolver = dummy.getPromiseResolver(_resolverId);
+ ok(promise instanceof Promise, "Returned a Promise");
+ ok(typeof _resolverId === "string", "resolverId is a string");
+ ok(resolver != null, "resolverId is a valid id");
+ next();
+ },
+ function() {
+ info("== Test getResolver()");
+ var id;
+ var resolver;
+ var promise = dummy.createPromise(function(resolve, reject) {
+ var r = { resolve: resolve, reject: reject };
+ id = dummy.getPromiseResolverId(r);
+ resolver = r;
+ ok(typeof id === "string", "id is a string");
+ r.resolve(true);
+ }).then(function(unused) {
+ var r = dummy.getPromiseResolver(id);
+ ok(resolver === r, "Get succeeded");
+ next();
+ });
+ },
+ function() {
+ info("== Test removeResolver");
+ var id;
+ var promise = dummy.createPromise(function(resolve, reject) {
+ var r = { resolve: resolve, reject: reject };
+ id = dummy.getPromiseResolverId(r);
+ ok(typeof id === "string", "id is a string");
+
+ var resolver = dummy.getPromiseResolver(id);
+ info("Got resolver " + JSON.stringify(resolver));
+ ok(resolver === r, "Resolver get succeeded");
+
+ r.resolve(true);
+ }).then(function(unused) {
+ dummy.removePromiseResolver(id);
+ var resolver = dummy.getPromiseResolver(id);
+ ok(resolver === undefined, "removeResolver: get failed");
+ next();
+ });
+ },
+ function() {
+ info("== Test takeResolver");
+ var id;
+ var resolver;
+ var promise = dummy.createPromise(function(resolve, reject) {
+ var r = { resolve: resolve, reject: reject };
+ id = dummy.getPromiseResolverId(r);
+ resolver = r;
+ ok(typeof id === "string", "id is a string");
+
+ var gotR = dummy.getPromiseResolver(id);
+ ok(gotR === r, "resolver get succeeded");
+
+ r.resolve(true);
+ }).then(function(unused) {
+ var r = dummy.takePromiseResolver(id);
+ ok(resolver === r, "take should succeed");
+
+ r = dummy.getPromiseResolver(id);
+ ok(r === undefined, "takeResolver: get failed");
+ next();
+ });
+ },
+ function() {
+ info("== Test window destroyed without messages and without GC");
+ checkWindowDestruction({ gc: false }, function(uninitCalled) {
+ ok(uninitCalled, "uninit() should have been called");
+ next();
+ });
+ },
+ function() {
+ info("== Test window destroyed without messages and with GC");
+ checkWindowDestruction({ gc: true }, function(uninitCalled) {
+ ok(!uninitCalled, "uninit() should NOT have been called");
+ next();
+ });
+ },
+ function() {
+ info("== Test window destroyed with weak messages and without GC");
+ checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
+ gc: false }, function(uninitCalled) {
+ ok(uninitCalled, "uninit() should have been called");
+ next();
+ });
+ },
+ function() {
+ info("== Test window destroyed with weak messages and with GC");
+ checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
+ gc: true }, function(uninitCalled) {
+ ok(!uninitCalled, "uninit() should NOT have been called");
+ next();
+ });
+ },
+ function() {
+ info("== Test window destroyed with strong messages and without GC");
+ checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
+ gc: false }, function(uninitCalled) {
+ ok(uninitCalled, "uninit() should have been called");
+ next();
+ });
+ },
+ function() {
+ info("== Test window destroyed with strong messages and with GC");
+ checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
+ gc: true }, function(uninitCalled) {
+ ok(uninitCalled, "uninit() should have been called");
+ next();
+ });
+ }
+ ];
+
+ function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+ }
+
+ function start() {
+ SimpleTest.waitForExplicitFinish();
+ next();
+ }
+ ]]>
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test"></pre>
+ </body>
+</window>
diff --git a/dom/base/test/test_domwindowutils.html b/dom/base/test/test_domwindowutils.html
new file mode 100644
index 0000000000..7485669d90
--- /dev/null
+++ b/dom/base/test/test_domwindowutils.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for DOMWindowUtils</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var utils = SpecialPowers.getDOMWindowUtils(window);
+function test_sendMouseEventDefaults() {
+ var x = 1, y = 2, button = 1, clickCount = 2,
+ modifiers = SpecialPowers.Ci.nsIDOMWindowUtils.MODIFIER_SHIFT;
+
+ window.addEventListener("mousedown", function(evt) {
+ // Mandatory args
+ // coordinates may change slightly due to rounding
+ ok((evt.clientX <= x+2) && (evt.clientX >= x-2), "check x");
+ ok((evt.clientY <= y+2) && (evt.clientY >= y-2), "check y");
+ is(evt.button, button, "check button");
+ is(evt.detail, clickCount, "check click count");
+ is(evt.getModifierState("Shift"), true, "check modifiers");
+
+ // Default value for optionals
+ is(evt.mozPressure, 0, "check pressure");
+ is(evt.mozInputSource, MouseEvent.MOZ_SOURCE_MOUSE, "check input source");
+ is(evt.isSynthesized, undefined, "check isSynthesized is undefined in content");
+ is(SpecialPowers.wrap(evt).isSynthesized, true, "check isSynthesized is true from chrome");
+ SimpleTest.executeSoon(next);
+ }, {once: true});
+
+ // Only pass mandatory arguments and check default values
+ utils.sendMouseEvent("mousedown", x, y, button, clickCount, modifiers);
+}
+
+function test_sendMouseEventOptionals() {
+ var x = 1, y = 2, button = 1, clickCount = 3,
+ modifiers = SpecialPowers.Ci.nsIDOMWindowUtils.MODIFIER_SHIFT,
+ pressure = 0.5,
+ source = MouseEvent.MOZ_SOURCE_KEYBOARD;
+
+ window.addEventListener("mouseup", function(evt) {
+ is(evt.mozInputSource, source, "explicit input source is valid");
+ is(SpecialPowers.wrap(evt).isSynthesized, false, "we can dispatch event that don't look synthesized");
+ SimpleTest.executeSoon(next);
+ }, {once: true});
+
+ // Check explicit value for optional args
+ utils.sendMouseEvent("mouseup", x, y, button, clickCount, modifiers,
+ false, pressure, source, false);
+}
+
+function test_sendMouseEvent4thButton() {
+ const x = 1, y = 2, button = 3, clickCount = 1, modifiers = 0;
+
+ window.addEventListener("mousedown", evt => {
+ is(evt.buttons, 2 ** button, "check button");
+ SimpleTest.executeSoon(next);
+ }, { once: true });
+
+ utils.sendMouseEvent("mousedown", x, y, button, clickCount, modifiers);
+}
+
+function test_sendMouseEvent5thButton() {
+ const x = 1, y = 2, button = 4, clickCount = 1, modifiers = 0;
+
+ window.addEventListener("mousedown", evt => {
+ is(evt.buttons, 2 ** button, "check button");
+ SimpleTest.executeSoon(next);
+ }, { once: true });
+
+ utils.sendMouseEvent("mousedown", x, y, button, clickCount, modifiers);
+}
+
+function test_getUnanimatedComputedStyle() {
+ SpecialPowers.pushPrefEnv(
+ {
+ set: [
+ ["dom.animations-api.core.enabled", true],
+ ["dom.animations-api.getAnimations.enabled", true],
+ ["dom.animations-api.timelines.enabled", true],
+ ],
+ },
+ () => {
+ window.open("file_domwindowutils_animation.html");
+ }
+ );
+}
+
+function test_setDynamicToolbarMaxHeight() {
+ window.open("file_domwindowutils_dynamic_toolbar.html");
+}
+
+var tests = [
+ test_sendMouseEventDefaults,
+ test_sendMouseEventOptionals,
+ test_sendMouseEvent4thButton,
+ test_sendMouseEvent5thButton,
+ test_getUnanimatedComputedStyle,
+ test_setDynamicToolbarMaxHeight
+];
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+function start() {
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.executeSoon(next);
+}
+
+window.addEventListener("load", start);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_element.matches.html b/dom/base/test/test_element.matches.html
new file mode 100644
index 0000000000..c47ee6024a
--- /dev/null
+++ b/dom/base/test/test_element.matches.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=886308
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 886308</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 886308 **/
+ ok(document.head.matches("head"), "head should match 'head'");
+ ok(document.querySelector("link").matches("html *"), "link is a descendant of 'html'");
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=886308">Mozilla Bug 886308</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_elementTraversal.html b/dom/base/test/test_elementTraversal.html
new file mode 100644
index 0000000000..ae9667db62
--- /dev/null
+++ b/dom/base/test/test_elementTraversal.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=444722
+-->
+<head>
+ <title>Test for the ElementTraversal spec</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="http://dev.w3.org/2006/webapi/ElementTraversal/publish/ElementTraversal.html">ElementTraversal</a>
+<div id="content" style="display: none">
+<span>span</span><div>div</div>
+<!--comment goes here-->
+<p id="p1">p1</p>
+text here
+<p id="p2">p2</p>
+<span>a<span>b</span>c<span>d</span>e</span>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var c = document.getElementById('content');
+var cc = c.children;
+
+var contents = ["span", "div", "p1", "p2", "abcde"];
+function testContent() {
+ for(i = 0, e = c.firstElementChild; e; e = e.nextElementSibling, i++) {
+ is(e.textContent, contents[i], "wrong element contents");
+ is(e, c.children[i], "wrong element");
+ is(e, c.children.item(i), "wrong element");
+ }
+ is(i, contents.length, "wrong number of element siblings");
+ is(i, c.childElementCount, "wrong number of child elements");
+ is(i, c.children.length, "wrong number of child elements");
+
+ // Nuke all elements to retest the child list.
+ c.innerHTML = c.innerHTML;
+
+ for(i--, e = c.lastElementChild; e; e = e.previousElementSibling, i--) {
+ is(e.textContent, contents[i], "g element contents");
+ is(e, c.children[i], "wrong element");
+ is(e, c.children.item(i), "wrong element");
+ }
+ is(i, -1, "wrong number of element siblings");
+}
+
+testContent();
+
+is(cc.length, 5, "wrong number of child elements");
+is(c.childElementCount, 5, "wrong number of child elements");
+
+var p1 = document.getElementById('p1');
+var p2 = document.getElementById('p2');
+is(p1.nextElementSibling, p2, "wrong sibling");
+is(p2.previousElementSibling, p1, "wrong sibling");
+
+u = document.createElement('u');
+u.textContent = 'u';
+c.insertBefore(u, p2);
+is(cc.length, 6, "wrong number of child elements");
+is(c.childElementCount, 6, "wrong number of child elements");
+is(p1.nextElementSibling, u, "wrong sibling");
+is(p2.previousElementSibling, u, "wrong sibling");
+
+contents.splice(3, 0, "u");
+testContent();
+
+var p1 = document.getElementById('p1');
+var p2 = document.getElementById('p2');
+c.removeChild(p1);
+c.removeChild(p2);
+is(cc.length, 4, "wrong number of child elements");
+is(c.childElementCount, 4, "wrong number of child elements");
+
+contents.splice(2, 1);
+contents.splice(3, 1);
+testContent();
+
+tw = document.createTreeWalker(document.documentElement,
+ NodeFilter.SHOW_ELEMENT,
+ null);
+e = document.documentElement;
+
+elemsTested = 0;
+done = false;
+while(!done) {
+ is(tw.currentNode, e, "wrong element:" + tw.currentNode + " != " + e);
+ elemsTested++;
+
+ if(tw.firstChild()) {
+ e = e.firstElementChild;
+ }
+ else {
+ while (!tw.nextSibling()) {
+ if (!tw.parentNode()) {
+ done = true;
+ break;
+ }
+ e = e.parentNode;
+ }
+ e = e.nextElementSibling;
+ }
+}
+is(elemsTested, document.getElementsByTagName("*").length,
+ "wrong number of elements");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_element_closest.html b/dom/base/test/test_element_closest.html
new file mode 100644
index 0000000000..2d06f2fbdd
--- /dev/null
+++ b/dom/base/test/test_element_closest.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1055533
+-->
+<head>
+ <title>Test for Bug 1055533</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 id="body">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1055533">Mozilla Bug 1055533</a>
+ <div id="test8" class="div3">
+ <div id="test7" class="div2">
+ <div id="test6" class="div1">
+ <form id="test10" class="form2"></form>
+ <form id="test5" class="form1" name="form-a">
+ <input id="test1" class="input1" required>
+ <fieldset class="fieldset2" id="test2">
+ <select id="test3" class="select1" required>
+ <option default id="test4" value="">Test4</option>
+ <option selected id="test11">Test11</option>
+ <option id="test12">Test12</option>
+ <option id="test13">Test13</option>
+ </select>
+ <input id="test9" type="text" required>
+ </fieldset>
+ </form>
+ </div>
+ </div>
+ </div>
+<script class="testbody" type="text/javascript">
+ test("select" , "test12", "test3");
+ test("fieldset" , "test13", "test2");
+ test("div" , "test13", "test6");
+ test("body" , "test3" , "body");
+
+ test("[default]" , "test4" , "test4");
+ test("[selected]" , "test4" , "");
+ test("[selected]" , "test11", "test11");
+ test('[name="form-a"]' , "test12", "test5");
+ test('form[name="form-a"]' , "test13", "test5");
+ test("input[required]" , "test9" , "test9");
+ test("select[required]" , "test9" , "");
+
+ test("div:not(.div1)" , "test13", "test7");
+ test("div.div3" , "test6" , "test8");
+ test("div#test7" , "test1" , "test7");
+
+ test(".div3 > .div2" , "test12", "test7");
+ test(".div3 > .div1" , "test12", "");
+ test("form > input[required]" , "test9" , "");
+ test("fieldset > select[required]", "test12", "test3");
+
+ test("input + fieldset" , "test6" , "");
+ test("form + form" , "test3" , "test5");
+ test("form + form" , "test5" , "test5");
+
+ test(":empty" , "test10", "test10");
+ test(":last-child" , "test11", "test2");
+ test(":first-child" , "test12", "test3");
+ test(":invalid" , "test11", "test2");
+
+ test(":scope" , "test4", "test4");
+ test("select > :scope" , "test4", "test4");
+ test("div > :scope" , "test4", "");
+ try {
+ test(":has(> :scope)" , "test4", "test3");
+ } catch(e) {
+ todo(false, ":has(> :scope) [:has is not implemented yet]");
+ }
+function test(aSelector, aElementId, aTargetId) {
+ var el = document.getElementById(aElementId).closest(aSelector);
+ if (el === null) {
+ is("", aTargetId, aSelector);
+ } else {
+ is(el.id, aTargetId, aSelector);
+ }
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_embed_xorigin_document.html b/dom/base/test/test_embed_xorigin_document.html
new file mode 100644
index 0000000000..3075f1897b
--- /dev/null
+++ b/dom/base/test/test_embed_xorigin_document.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>test for embedding a cross-origin document</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+
+
+<script>
+// Get the path of the current test, without hostname or filename.
+const testPath = window.location.href.replace("http://mochi.test:8888", "");
+const testDir = testPath.substring(0, testPath.lastIndexOf('/') + 1);
+const embedHasBrowsingContext = SpecialPowers.getBoolPref("browser.opaqueResponseBlocking.syntheticBrowsingContext", false);
+const imageTypeORB = embedHasBrowsingContext
+ ? SpecialPowers.Ci.nsIObjectLoadingContent.TYPE_DOCUMENT
+ : SpecialPowers.Ci.nsIObjectLoadingContent.TYPE_IMAGE;
+
+const imageTypeStringORB = embedHasBrowsingContext ? "document" : "image";
+
+add_task(async function() {
+ // FIXME: Remove when bug 1658342 is fixed
+ await SpecialPowers.pushPrefEnv({
+ set: [["fission.remoteObjectEmbed", true]],
+ });
+
+ info("Loading image in embed");
+ let embed = document.createElement("embed");
+ document.body.appendChild(embed);
+
+ info("x-site image load from element");
+ embed.setAttribute("src", "http://example.com" + testDir + "green.png");
+ await new Promise(resolve => embed.addEventListener("load", resolve, { once: true }));
+ is(
+ SpecialPowers.wrap(embed).displayedType,
+ imageTypeORB,
+ `image load should have ${imageTypeStringORB} type`
+ );
+
+ if (!embedHasBrowsingContext) {
+ ok(!SpecialPowers.wrap(embed).frameLoader, "should not have frameloader");
+ ok(!SpecialPowers.wrap(embed).browsingContext, "should not have bc");
+ } else {
+ ok(SpecialPowers.wrap(embed).frameLoader, "should have frameloader");
+ ok(SpecialPowers.wrap(embed).browsingContext, "should have bc");
+ }
+
+ info("x-site document load from element");
+ embed.setAttribute("src", "http://example.com" + testDir + "file_empty.html");
+ await new Promise(resolve => embed.addEventListener("load", resolve, { once: true }));
+ is(
+ SpecialPowers.wrap(embed).displayedType,
+ SpecialPowers.Ci.nsIObjectLoadingContent.TYPE_DOCUMENT,
+ "document load should have document type"
+ );
+ ok(SpecialPowers.wrap(embed).frameLoader, "should have frameloader");
+ ok(SpecialPowers.wrap(embed).browsingContext, "should have bc");
+
+ info("load x-site document in iframe & compare processes");
+ let iframe = document.createElement("iframe");
+ iframe.setAttribute("src", "http://example.com" + testDir + "file_empty.html");
+ document.body.appendChild(iframe);
+ await new Promise(resolve => iframe.addEventListener("load", resolve, { once: true }));
+
+ let embedRemoteType = await SpecialPowers.spawn(embed, [], () => Services.appinfo.remoteType);
+ let iframeRemoteType = await SpecialPowers.spawn(iframe, [], () => Services.appinfo.remoteType);
+ is(iframeRemoteType, embedRemoteType, "remote types should match");
+
+ info("x-site image load from docshell");
+ SpecialPowers.spawn(embed, ["http://example.com" + testDir + "green.png"], uri => {
+ content.location.href = uri;
+ })
+ await new Promise(resolve => embed.addEventListener("load", resolve, { once: true }));
+ is(
+ SpecialPowers.wrap(embed).displayedType,
+ SpecialPowers.Ci.nsIObjectLoadingContent.TYPE_DOCUMENT,
+ "image load via location should have document type"
+ );
+ ok(SpecialPowers.wrap(embed).frameLoader, "should have frameloader");
+ ok(SpecialPowers.wrap(embed).browsingContext, "should have bc");
+
+ info("x-site image load from element");
+ embed.setAttribute("src", "http://example.com" + testDir + "green.png");
+ await new Promise(resolve => embed.addEventListener("load", resolve, { once: true }));
+ is(
+ SpecialPowers.wrap(embed).displayedType,
+ imageTypeORB,
+ `image load should have ${imageTypeStringORB} type`
+ );
+
+ if (!embedHasBrowsingContext) {
+ ok(!SpecialPowers.wrap(embed).frameLoader, "should not have frameloader");
+ ok(!SpecialPowers.wrap(embed).browsingContext, "should not have bc");
+ } else {
+ ok(SpecialPowers.wrap(embed).frameLoader, "should have frameloader");
+ ok(SpecialPowers.wrap(embed).browsingContext, "should have bc");
+ }
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_encodeToStringWithMaxLength.html b/dom/base/test/test_encodeToStringWithMaxLength.html
new file mode 100644
index 0000000000..c3d6f509e3
--- /dev/null
+++ b/dom/base/test/test_encodeToStringWithMaxLength.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=995321
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 995321 - encodeToStringWithMaxLength</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ function getEncoder() {
+ // Create a plaintext encoder without flags.
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("text/plain");
+ encoder.init(document, "text/plain", 0);
+ return encoder;
+ }
+
+ function testPlaintextSerializerWithMaxLength() {
+ var string = getEncoder().encodeToString();
+
+ var shorterString = getEncoder().encodeToStringWithMaxLength(1);
+ ok(shorterString.length < 1 + 72,
+ "test length is in the expected range after limiting the length to 1");
+ ok(string.startsWith(shorterString.trimRight()),
+ "the shorter string has the expected content");
+
+ shorterString = getEncoder().encodeToStringWithMaxLength(300);
+ ok(shorterString.length < 300 + 72,
+ "test length is in the expected range after limiting the length to 300");
+ ok(string.startsWith(shorterString.trimRight()),
+ "the shorter string has the expected content");
+
+ is(getEncoder().encodeToStringWithMaxLength(0), string,
+ "limiting the length to 0 should be ignored");
+
+ is(getEncoder().encodeToStringWithMaxLength(10000), string,
+ "limiting the length to a huge value should return the whole page");
+
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(testPlaintextSerializerWithMaxLength);
+ SimpleTest.waitForExplicitFinish();
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=995321">Mozilla Bug 995321</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+The <em>Mozilla</em> project is a global community of <strong>people</strong> who believe that openness, innovation, and opportunity are key to the continued health of the Internet. We have worked together since 1998 to ensure that the Internet is developed in a way that benefits everyone. We are best known for creating the Mozilla Firefox web browser.
+
+The Mozilla project uses a community-based approach to create world-class open source software and to develop new types of collaborative activities. We create communities of people involved in making the Internet experience better for all of us.
+
+As a result of these efforts, we have distilled a set of principles that we believe are critical for the Internet to continue to benefit the public good as well as commercial aspects of life. We set out these principles below.
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_encodeToStringWithRequiresReinitAfterOutput.html b/dom/base/test/test_encodeToStringWithRequiresReinitAfterOutput.html
new file mode 100644
index 0000000000..a1d2749ef8
--- /dev/null
+++ b/dom/base/test/test_encodeToStringWithRequiresReinitAfterOutput.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1352882
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1352882 - RequiresReinitAfterOutput</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ function getEncoder() {
+ // Create a plaintext encoder without flags.
+ var encoder = SpecialPowers.Cu.createDocumentEncoder("text/plain");
+ encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
+ return encoder;
+ }
+
+ function testPlaintextSerializerWithRequiresReinitAfterOutput() {
+ var encoder = getEncoder();
+
+ var str = encoder.encodeToString();
+ ok(str, "encodingToString should be successful");
+
+ SimpleTest.doesThrow(() => {
+ encoder.encodeToString();
+ }, 'encodeToString should throw exception if it has RequiresReinitAfterOutput and it is called twice');
+
+ encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
+ str = encoder.encodeToString();
+ ok(str, "encodingToString should be successful after calling init again");
+
+ encoder = getEncoder();
+
+ str = encoder.encodeToStringWithMaxLength(1000);
+ ok(str, "encodingToString should be successful");
+
+ SimpleTest.doesThrow(() => {
+ encoder.encodeToStringWithMaxLength(1000);
+ }, 'encodeToStringWithMaxLength should throw exception if it has RequiresReinitAfterOutput and it is called twice');
+
+ encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
+ str = encoder.encodeToStringWithMaxLength(1000);
+ ok(str, "encodingToStringWithMaxLength should be successful after calling init again");
+
+ encoder = getEncoder();
+
+ const UINT32_MAX = 4294967295;
+ let pipe = SpecialPowers.Cc["@mozilla.org/pipe;1"].createInstance(SpecialPowers.Ci.nsIPipe);
+ pipe.init(true, true, 0, UINT32_MAX, null);
+ let stream = pipe.outputStream;
+
+ encoder.setCharset("utf-8");
+ encoder.encodeToStream(stream);
+ ok(str, "encodingToStream should be successful");
+
+ SimpleTest.doesThrow(() => {
+ encoder.encodeToStream(stream);
+ }, 'encodeToStream should throw exception if it has RequiresReinitAfterOutput and it is called twice');
+
+ encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
+ encoder.encodeToStream(stream);
+ ok(true, "encodingToStream should be successful after calling init again");
+
+ stream.close();
+
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(testPlaintextSerializerWithRequiresReinitAfterOutput);
+ SimpleTest.waitForExplicitFinish();
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1352882">Mozilla Bug 1352882</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+The <em>Mozilla</em> project is a global community of <strong>people</strong> who believe that openness, innovation, and opportunity are key to the continued health of the Internet. We have worked together since 1998 to ensure that the Internet is developed in a way that benefits everyone. We are best known for creating the Mozilla Firefox web browser.
+
+The Mozilla project uses a community-based approach to create world-class open source software and to develop new types of collaborative activities. We create communities of people involved in making the Internet experience better for all of us.
+
+As a result of these efforts, we have distilled a set of principles that we believe are critical for the Internet to continue to benefit the public good as well as commercial aspects of life. We set out these principles below.
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_eventsource_event_listener_leaks.html b/dom/base/test/test_eventsource_event_listener_leaks.html
new file mode 100644
index 0000000000..d775b2f193
--- /dev/null
+++ b/dom/base/test/test_eventsource_event_listener_leaks.html
@@ -0,0 +1,40 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1450358 - Test EventSource event listener leak conditions</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/dom/events/test/event_leak_utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+// Manipulate EventSource. Its important here that we create a
+// listener callback from the DOM objects back to the frame's global
+// in order to exercise the leak condition.
+async function useEventSource(contentWindow) {
+ let es = new contentWindow.EventSource("delayedServerEvents.sjs");
+ es.onmessage = _ => {
+ contentWindow.messageCount += 1;
+ };
+}
+
+async function runTest() {
+ try {
+ await checkForEventListenerLeaks("EventSource", useEventSource);
+ } catch (e) {
+ ok(false, e);
+ } finally {
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+addEventListener("load", runTest, { once: true });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_eventsourceservice_basic.html b/dom/base/test/test_eventsourceservice_basic.html
new file mode 100644
index 0000000000..da08fb0cd9
--- /dev/null
+++ b/dom/base/test/test_eventsourceservice_basic.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>EventSource event service basic test</title>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var service = SpecialPowers.Cc["@mozilla.org/eventsourceevent/service;1"]
+ .getService(SpecialPowers.Ci.nsIEventSourceEventService);
+ok(!!service, "We have the nsIEventSourceEventService");
+
+var innerId = SpecialPowers.wrap(window).windowGlobalChild.innerWindowId;
+ok(innerId, "We have a valid innerWindowID: " + innerId);
+
+var channelId = null;
+var listener = {
+ QueryInterface(aIID) {
+ if (
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIEventSourceEventListener)
+ ) {
+ return this;
+ }
+ throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
+ },
+ eventSourceConnectionOpened(httpChannelId) {
+ info("eventSourceConnectionOpened");
+ ok(httpChannelId > 0, "Channel ID received");
+ channelId = httpChannelId;
+ },
+ eventSourceConnectionClosed(httpChannelId) {
+ info("eventSourceConnectionClosed");
+ ok(httpChannelId > 0, "Channel ID received");
+ ok(httpChannelId === channelId, "Channel ID matched");
+ service.removeListener(innerId, listener);
+ ok(true, "Listener removed");
+ ok(!service.hasListenerFor(innerId), "hasListenerFor(innerId) should be false");
+ SimpleTest.finish();
+ },
+ eventReceived(httpChannelId, eventName, lastEventId, data, retry, timeStamp) {
+ info("eventReceived");
+ is(eventName, "message", "Event name is 'message'");
+ is(lastEventId, "1", "Last event id is '1'");
+ is(data, "msg 1", "Data is 'msg 1'");
+ ok(retry > 0, "Reconnection time received");
+ ok(httpChannelId === channelId, "Channel ID matched");
+ ok(timeStamp > 0, "TimeStamp received");
+ }
+}
+
+service.addListener(innerId, listener);
+ok(true, "Listener added");
+ok(service.hasListenerFor(innerId), "hasListenerFor(innerId) should be true");
+addLoadEvent(function () {
+ const es = new EventSource("http://mochi.test:8888/tests/dom/base/test/eventsource_message.sjs");
+ es.onmessage = function (e) {
+ es.close();
+ };
+});
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_eventsourceservice_reconnect_error.html b/dom/base/test/test_eventsourceservice_reconnect_error.html
new file mode 100644
index 0000000000..cb124693c9
--- /dev/null
+++ b/dom/base/test/test_eventsourceservice_reconnect_error.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>EventSource event service reconnect error test</title>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var service = SpecialPowers.Cc["@mozilla.org/eventsourceevent/service;1"]
+ .getService(SpecialPowers.Ci.nsIEventSourceEventService);
+ok(!!service, "We have the nsIEventSourceEventService");
+
+var innerId = SpecialPowers.wrap(window).windowGlobalChild.innerWindowId;
+ok(innerId, "We have a valid innerWindowID: " + innerId);
+
+var channelId;
+var count = {
+ open: 0,
+ msg: 0,
+ close: 0
+};
+var listener = {
+ QueryInterface(aIID) {
+ if (
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIEventSourceEventListener)
+ ) {
+ return this;
+ }
+ throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
+ },
+ eventSourceConnectionOpened(httpChannelId) {
+ info("eventSourceConnectionOpened");
+ ok(httpChannelId > 0, "Channel ID received");
+ channelId = httpChannelId;
+ count.open++;
+ },
+ eventSourceConnectionClosed(httpChannelId) {
+ info("eventSourceConnectionClosed");
+ ok (httpChannelId === channelId, "Channel was closed on failure");
+ count.close++;
+ SimpleTest.requestFlakyTimeout("Test for open/close");
+ setTimeout(checkCallsCount, 2000);
+ },
+ eventReceived(httpChannelId, eventName, lastEventId, data, retry, timeStamp) {
+ info("eventReceived=", retry);
+ is(eventName, "message", "Event name is 'message'");
+ count.msg++;
+ }
+}
+
+service.addListener(innerId, listener);
+ok(true, "Listener added");
+addLoadEvent(function () {
+ const es = new EventSource("http://mochi.test:8888/tests/dom/base/test/eventsource_reconnect.sjs?id=" + Date.now());
+});
+SimpleTest.waitForExplicitFinish();
+
+function checkCallsCount() {
+ ok(count.open == 1, "No new open event");
+ ok(count.close == 1, "No new close event");
+ ok(count.msg == 1, "No new message event");
+ SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_eventsourceservice_status_error.html b/dom/base/test/test_eventsourceservice_status_error.html
new file mode 100644
index 0000000000..55be8e0dc7
--- /dev/null
+++ b/dom/base/test/test_eventsourceservice_status_error.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>EventSource event service status error test</title>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var service = SpecialPowers.Cc["@mozilla.org/eventsourceevent/service;1"]
+ .getService(SpecialPowers.Ci.nsIEventSourceEventService);
+ok(!!service, "We have the nsIEventSourceEventService");
+
+var innerId = SpecialPowers.wrap(window).windowGlobalChild.innerWindowId;
+ok(innerId, "We have a valid innerWindowID: " + innerId);
+
+var listener = {
+ QueryInterface(aIID) {
+ if (
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIEventSourceEventListener)
+ ) {
+ return this;
+ }
+ throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
+ },
+ eventSourceConnectionOpened(httpChannelId) {
+ ok(false, "This should not happen");
+ },
+ eventSourceConnectionClosed(httpChannelId) {
+ ok(false, "This should not happen");
+ },
+ eventReceived(httpChannelId, eventName, lastEventId, data, retry, timeStamp) {
+ ok(false, "This should not happen");
+ }
+}
+
+service.addListener(innerId, listener);
+ok(true, "Listener added");
+
+var NUM_TESTS = 2;
+addLoadEvent(function () {
+ doTest(404);
+ doTest(502);
+});
+
+SimpleTest.waitForExplicitFinish();
+
+var count = 0;
+function doTest(status) {
+ const es = new EventSource(
+ "http://mochi.test:8888/tests/dom/base/test/eventsource_message.sjs?status=" + status
+ );
+ es.onerror = function (e) {
+ count++;
+ if (count >= NUM_TESTS) {
+ SimpleTest.finish();
+ }
+ }
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_eventsourceservice_worker.html b/dom/base/test/test_eventsourceservice_worker.html
new file mode 100644
index 0000000000..99c89f4e50
--- /dev/null
+++ b/dom/base/test/test_eventsourceservice_worker.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>EventSource event service worker test</title>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var service = SpecialPowers.Cc["@mozilla.org/eventsourceevent/service;1"]
+ .getService(SpecialPowers.Ci.nsIEventSourceEventService);
+ok(!!service, "We have the nsIEventSourceEventService");
+
+var innerId = SpecialPowers.wrap(window).windowGlobalChild.innerWindowId;
+ok(innerId, "We have a valid innerWindowID: " + innerId);
+
+var channelId = null;
+var listener = {
+ QueryInterface(aIID) {
+ if (
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
+ SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIEventSourceEventListener)
+ ) {
+ return this;
+ }
+ throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
+ },
+ eventSourceConnectionOpened(httpChannelId) {
+ info("eventSourceConnectionOpened");
+ ok(httpChannelId > 0, "Channel ID received");
+ channelId = httpChannelId;
+ },
+ eventSourceConnectionClosed(httpChannelId) {
+ info("eventSourceConnectionClosed");
+ ok(httpChannelId === channelId, "Channel ID matched");
+ SimpleTest.finish();
+ },
+ eventReceived(httpChannelId, eventName, lastEventId, data, retry, timeStamp) {
+ info("eventReceived");
+ is(eventName, "message", "Event name is 'message'");
+ is(lastEventId, "1", "Last event id is '1'");
+ is(data, "msg 1", "Data is 'msg 1'");
+ ok(retry > 0, "Reconnection time received");
+ ok(httpChannelId === channelId, "Channel ID matched");
+ ok(timeStamp > 0, "TimeStamp received");
+ }
+}
+
+service.addListener(innerId, listener);
+ok(true, "Listener added");
+addLoadEvent(function () {
+ const worker = new Worker("eventsource_worker.js");
+});
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_explicit_user_agent.html b/dom/base/test/test_explicit_user_agent.html
new file mode 100644
index 0000000000..58dffac67e
--- /dev/null
+++ b/dom/base/test/test_explicit_user_agent.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for XMLHttpRequest.GetResponseHeader(foo) byte-inflates the output</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <meta charset="utf-8">
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript">
+ "use strict";
+
+ add_task(async function() {
+ await new Promise((r) => {
+ let xhr = new XMLHttpRequest();
+ xhr.open('GET', 'file_explicit_user_agent.sjs', true);
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ is(xhr.getResponseHeader("Result-User-Agent"), navigator.userAgent,
+ "The resulting user-agent is the navigator's UA");
+ r();
+ }
+ }
+ xhr.send(null);
+ });
+
+ await new Promise((r) => {
+ let xhr = new XMLHttpRequest();
+ xhr.open('GET', 'file_explicit_user_agent.sjs', true);
+ xhr.setRequestHeader('User-Agent', 'custom-ua/10.0');
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ is(xhr.getResponseHeader("Result-User-Agent"), 'custom-ua/10.0',
+ "The resulting user-agent is the custom UA");
+ r();
+ }
+ }
+ xhr.send(null);
+ });
+
+ var response = await fetch('file_explicit_user_agent.sjs', {
+ method: 'GET'
+ });
+ is(response.headers.get("Result-User-Agent"), navigator.userAgent,
+ "The user-agent is the navigator's UA");
+
+ var headers = new Headers();
+ headers.set('User-Agent', 'custom-ua/20.0');
+ var response2 = await fetch('file_explicit_user_agent.sjs', {
+ method: 'GET',
+ headers,
+ });
+ is(response2.headers.get("Result-User-Agent"), 'custom-ua/20.0',
+ "The user-agent is the custom UA");
+ });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_find.html b/dom/base/test/test_find.html
new file mode 100644
index 0000000000..4b71bba4ff
--- /dev/null
+++ b/dom/base/test/test_find.html
@@ -0,0 +1,204 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const t = async_test("Test window.find / nsFind");
+
+function testFindable(findCount, textToFind, buildDoc, description) {
+ if (typeof findCount == "boolean")
+ findCount = findCount ? 1 : 0;
+ try {
+ const iframe = document.querySelector("iframe")
+ iframe.contentDocument.documentElement.innerHTML =
+ (typeof buildDoc == "string") ? buildDoc : "";
+
+ if (typeof buildDoc == "function")
+ buildDoc(iframe.contentDocument);
+
+ iframe.contentWindow.getSelection().removeAllRanges();
+ for (let i = findCount; i >= 0; --i) {
+ const expectFindable = i != 0;
+ assert_equals(
+ iframe.contentWindow.find(textToFind),
+ expectFindable,
+ "Should be " + (expectFindable ? "" : "not ") + "findable: " + description + ", text: " + textToFind + ", iter: " + (findCount - i + 1)
+ );
+ }
+
+ } catch (ex) {
+ assert_unreached(ex);
+ }
+}
+
+const INLINE_LIKE_DISPLAY_VALUES = [
+ "inline",
+ "inline-grid",
+ "inline-block",
+ "inline-flex",
+];
+
+const BLOCK_LIKE_DISPLAY_VALUES = [
+ "block",
+ "flex",
+ "grid",
+ "list-item",
+ "table-column-group",
+ "table-column",
+ "table-footer-group",
+ "table-header-group",
+ "table-row-group",
+ "table-row",
+ "table",
+];
+
+let runTests = t.step_func_done(function() {
+ testFindable(true, "me and me", `
+ me <div style="display: contents">and</div> me
+ `, "display: contents");
+
+ testFindable(true, "me me", `
+ me <div style="display: none">and</div> me
+ `, "display: none");
+
+ testFindable(false, "me and me", `
+ me <div style="display: none">and</div> me
+ `, "display: none");
+
+ for (const display of INLINE_LIKE_DISPLAY_VALUES) {
+ testFindable(true, "me and me", `
+ me <div style="display: ${display}">and</div> me
+ `, "div display: " + display);
+ testFindable(true, "me and me", `
+ me <span style="display: ${display}">and</span> me
+ `, "span display: " + display);
+ }
+
+ for (const display of BLOCK_LIKE_DISPLAY_VALUES) {
+ testFindable(false, "me and me", `
+ me <div style="display: ${display}">and</div> me
+ `, "div display: " + display);
+ testFindable(false, "me and me", `
+ me <span style="display: ${display}">and</span> me
+ `, "span display: " + display);
+ }
+
+ testFindable(false, "me and me", `
+ me <fieldset>and</fieldset> me
+ `);
+
+ testFindable(true, "This text should be visible", `
+ <div style="visibility: hidden">
+ <div style="visibility: visible">
+ This text should be visible
+ </div>
+ </div>
+ `);
+
+ testFindable(true, "This text should be visible", `
+ <style>:root { overflow: hidden }</style>
+ <div style="overflow: auto;">
+ <div style="height: 300vh"></div>
+ This text should be visible
+ </div>
+ `);
+
+ testFindable(true, "foobar", `
+ <body><script style="display: block;">foobar</` + `script></body>
+ `);
+
+
+ testFindable(true, "Shadow text", function(document) {
+ let div = document.createElement("div");
+ div.attachShadow({ mode: "open" }).innerHTML = `
+ Wohoo, this is Shadow text, yay!
+ `;
+ document.documentElement.appendChild(div);
+ }, "In Shadow DOM");
+
+ testFindable(true, "Shadow text", function(document) {
+ let div = document.createElement("div");
+ div.appendChild(document.createTextNode(
+ "Wohoo, this is Shadow text, yay!"
+ ));
+ div.attachShadow({ mode: "open" }).innerHTML = `<slot></slot>`;
+ document.documentElement.appendChild(div);
+ }, "Slotted content in Shadow DOM");
+
+ // TODO(emilio): This should work in an ideal world.
+ testFindable(false, "Shadow text", function(document) {
+ let div = document.createElement("div");
+ div.appendChild(document.createTextNode("text, yay!"));
+ div.attachShadow({ mode: "open" }).innerHTML = `This is Shadow <slot></slot>`;
+ document.documentElement.appendChild(div);
+ }, "Mixed shadow and non-shadow text");
+
+ testFindable(true, "Shadow", function(document) {
+ document.documentElement.innerHTML = `
+ Sources<span id="host"></span>
+ <div>whatever</div>
+ `;
+ document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = "Shadow text";
+ }, "Test inside a shadow-root mid-match");
+
+ testFindable(false, "Outside shadow", function(document) {
+ document.documentElement.innerHTML = `
+ Outside <div id="host"></div> shadow
+ `;
+ document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = "inside shadow";
+ }, "Block in different subtree");
+
+ // NOTE(emilio): It is probably doable / worth changing this to return true,
+ // maybe, by relaxing the security checks in the ranges nsFind returns or
+ // such.
+ //
+ // See bug 1442466 / bug 1510485 / bug 1505887.
+ testFindable(false, "foo", function(document) {
+ let input = document.createElement("input");
+ input.value = "foo";
+ document.documentElement.appendChild(input);
+ }, "Native anonymous content isn't exposed in window.find");
+
+ // Same as above, but in this case the check is warranted, we shouldn't
+ // expose this range.
+ testFindable(false, "find me", `
+ <style>div::before { content: "Do find me" }</style>
+ <div></div>
+ `, "Pseudo-element");
+
+ // Same as above.
+ testFindable(false, "find me", `
+ <img alt="Do find me">
+ `, "Image alt content");
+
+ // Same as above.
+ testFindable(false, "find me", `
+ <input type="submit" value="Do find me">
+ `, "Submit input value");
+
+ testFindable(false, "\0", `
+ &#0;
+ `);
+
+ testFindable(true, "\0", function(document) {
+ document.documentElement.appendChild(document.createTextNode("\0"));
+ }, "Inserted null characters are findable");
+
+ testFindable(false, "ab", `a<br>b`, "<br> forces a break even if there's no whitespace in between");
+
+ testFindable(true, "history.kafka", `
+ <code>database.history&#8203;.kafka.bootstrap.servers</code>
+ `, "ZWSP should be ignored");
+
+ testFindable(2, " ", "a b c", "Collapsed whitespace");
+});
+
+window.onload = function() {
+ let iframe = document.createElement("iframe");
+ iframe.onload = runTests;
+ iframe.srcdoc = "<!doctype html><html></html>";
+ document.body.appendChild(iframe);
+};
+</script>
+</body>
diff --git a/dom/base/test/test_find_bug1601118.html b/dom/base/test/test_find_bug1601118.html
new file mode 100644
index 0000000000..de4604bc45
--- /dev/null
+++ b/dom/base/test/test_find_bug1601118.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="container">
+ Fission <br/>
+ Some text <br/>
+ Some more text Fission or Fission or even <span>Fi</span>ssion<br/>
+ Fission <br/>
+ more text<br/>
+ <div>
+ in a nested block Fission stuff
+ </div>
+</div>
+<script>
+const kContainer = document.getElementById("container");
+const kExpectedCount = 6;
+
+// We expect surroundContents() to throw in the <span>Fi</span>ssion case.
+const kExpectedThrewCount = 1;
+
+// Keep a hang of the original DOM so as to test forwards and backwards navigation.
+const kContainerClone = kContainer.cloneNode(true);
+
+function advance(backwards) {
+ if (!window.find("Fiss", /* caseSensitive = */ true, backwards))
+ return { success: false };
+
+ let threw = false;
+ try {
+ window.getSelection().getRangeAt(0).surroundContents(document.createElement("mark"));
+ } catch (ex) {
+ threw = true;
+ }
+
+ // Sanity-check
+ assert_equals(window.getSelection().toString(), "Fiss");
+ return { success: true, threw };
+}
+
+function runTestForDirection(backwards) {
+ let threwCount = 0;
+ for (let i = 0; i < kExpectedCount; ++i) {
+ let result = advance(backwards);
+ assert_true(result.success, `Should've successfully advanced (${i} / ${kExpectedCount}, backwards: ${backwards})`);
+ if (result.threw)
+ threwCount++;
+ }
+ assert_false(advance(backwards).success, `Should've had exactly ${kExpectedCount} matches`);
+ assert_equals(threwCount, kExpectedThrewCount, "Should've thrown the expected number of times");
+ assert_equals(kContainer.querySelectorAll("mark").length, kExpectedCount - threwCount, "Should've created the expected number of marks");
+ assert_false(!!kContainer.querySelector("mark mark"), "Shouldn't have created nested marks");
+}
+
+test(function() {
+ runTestForDirection(false);
+ window.getSelection().removeAllRanges();
+ kContainer.innerHTML = kContainerClone.innerHTML;
+ runTestForDirection(true);
+}, "window.find() while marking with surroundContents");
+</script>
diff --git a/dom/base/test/test_find_bug1654683.html b/dom/base/test/test_find_bug1654683.html
new file mode 100644
index 0000000000..c4a8aea8af
--- /dev/null
+++ b/dom/base/test/test_find_bug1654683.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div class="before">
+ mozilla before
+</div>
+<input value="mozilla">
+<div class="after">
+ mozilla after
+</div>
+<script>
+function selectionContainedWithin(selector) {
+ for (let node = getSelection().anchorNode; node; node = node.parentNode) {
+ if (node.matches && node.matches(selector))
+ return true;
+ }
+ return false;
+}
+
+test(function () {
+ let input = document.querySelector("input");
+ input.focus();
+ assert_true(window.find("mozilla"), "Found the string, didn't throw");
+ assert_true(selectionContainedWithin(".after"), "Should've found the following node");
+ assert_true(!window.find("mozilla"), "No more matches forward");
+ assert_true(window.find("mozilla", /* caseSensitive = */ false, /* backwards = */ true), "Should find stuff backwards");
+ assert_true(selectionContainedWithin(".before"), "Should've found the node before the input (should not return the NAC range)");
+}, "window.find() doesn't throw if focused on an <input>");
+</script>
diff --git a/dom/base/test/test_find_nac.html b/dom/base/test/test_find_nac.html
new file mode 100644
index 0000000000..66bde6bbeb
--- /dev/null
+++ b/dom/base/test/test_find_nac.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<input value="bar">
+<script>
+test(function() {
+ // The exact return value of this first call is tested in
+ // test_find.html.
+ window.find("bar");
+ assert_false(window.find("bar"));
+}, "window.find doesn't get stuck on NAC");
+</script>
diff --git a/dom/base/test/test_focus_design_mode.html b/dom/base/test/test_focus_design_mode.html
new file mode 100644
index 0000000000..331dff2094
--- /dev/null
+++ b/dom/base/test/test_focus_design_mode.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1690747
+-->
+<head>
+ <title>Test for Bug 1690747</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=1690747">Mozilla Bug 1690747</a>
+<p id="display"></p>
+<div id='content'>
+</div>
+<pre id="test">
+<iframe src="https://example.org/tests/dom/base/test/file_focus_design_mode_inner.html"></iframe>
+<script type="application/javascript">
+
+/** Test for Bug 1690747 **/
+
+let iframe = document.querySelector("iframe");
+
+function waitForEvent(target, event, checkFn) {
+ return new Promise(resolve => {
+ target.addEventListener(event, e => {
+ if (checkFn && !checkFn(e)) {
+ return;
+ }
+ resolve();
+ }, { once: true });
+ });
+}
+
+async function getLog() {
+ let log = "";
+ SimpleTest.executeSoon(function() {
+ iframe.contentWindow.postMessage("getlog", "*");
+ });
+ await waitForEvent(window, "message", (e) => {
+ log = e.data;
+ return true;
+ });
+ return log;
+}
+
+add_setup(async function() {
+ await SpecialPowers.pushPrefEnv({ set: [["dom.disable_window_flip", true]] });
+});
+
+add_task(async function activeElementAfterBluring() {
+ iframe.contentWindow.postMessage("focus", "*");
+ is(await getLog(), "innerlog:windowfocus,activeElement:HTML,", "check activeElement");
+ iframe.contentWindow.blur();
+ is(await getLog(), "innerlog:windowfocus,activeElement:HTML,activeElement:HTML,", "check activeElement after bluring");
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_focus_display_none_xorigin_iframe.html b/dom/base/test/test_focus_display_none_xorigin_iframe.html
new file mode 100644
index 0000000000..b04141b0fe
--- /dev/null
+++ b/dom/base/test/test_focus_display_none_xorigin_iframe.html
@@ -0,0 +1,134 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1716762
+-->
+<head>
+<meta charset="utf-8">
+<title>Test for Bug 1716762</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=1716762">Mozilla Bug 1716762</a><br>
+<input></input><br>
+<div id="target" style="display: none;">
+<iframe src="http://example.org/tests/dom/base/test/file_focus_display_none_xorigin_iframe_inner.html"></iframe>
+</div>
+<script type="text/javascript">
+
+let waitForMessage = function(aMsg) {
+ return new Promise(reslove => {
+ window.addEventListener("message", function handler(e) {
+ info(`main received message: ${e.data}`);
+ if (e.data === aMsg) {
+ window.removeEventListener("message", handler);
+ reslove();
+ }
+ });
+ });
+};
+
+let sendMessage = async function(aWindow, aMsg) {
+ aWindow.postMessage(aMsg, "*");
+ await waitForMessage("done");
+}
+
+let getFocus = function(aWindow) {
+ return new Promise(reslove => {
+ window.addEventListener("message", function handler(e) {
+ info(e.data);
+ reslove(e.data);
+ }, { once: true });
+ aWindow.postMessage("getfocus", "*");
+ });
+}
+
+/** Test for Bug 1716762 **/
+
+let input = document.querySelector("input");
+let iframe = document.querySelector("iframe");
+
+add_task(async function test_ancestor_display_none_init() {
+ // focus input element
+ input.focus();
+ is(document.activeElement.tagName, "INPUT", "focus should move to input element");
+
+ // focus input element in hidden iframe
+ await sendMessage(iframe.contentWindow, "focus");
+ is(document.activeElement.tagName, "INPUT", "focus should stay on input element");
+});
+
+add_task(async function test_remove_ancestor_display_none() {
+ // remove `display: none` from the ancestor of iframe
+ document.getElementById("target").style = "";
+ document.body.offsetWidth;
+
+ // focus input element
+ input.focus();
+ is(document.activeElement.tagName, "INPUT", "focus should move to input element");
+
+ // focus input element in hidden iframe
+ await sendMessage(iframe.contentWindow, "focus");
+ is(document.activeElement.tagName, "IFRAME", "focus should move to iframe element");
+});
+
+add_task(async function test_ancestor_display_none() {
+ // add `display: none` to the ancestor of iframe back
+ document.getElementById("target").style = "display: none;";
+ document.body.offsetWidth;
+
+ // focus input element
+ input.focus();
+ is(document.activeElement.tagName, "INPUT", "focus should move to input element");
+
+ // focus input element in hidden iframe
+ await sendMessage(iframe.contentWindow, "focus");
+ is(document.activeElement.tagName, "INPUT", "focus should stay on input element");
+});
+
+add_task(async function test_remove_ancestor_display_none_again() {
+ // remove `display: none` from the ancestor of iframe
+ document.getElementById("target").style = "";
+ document.body.offsetWidth;
+
+ // focus input element
+ input.focus();
+ is(document.activeElement.tagName, "INPUT", "focus should move to input element");
+
+ // focus input element in hidden iframe
+ await sendMessage(iframe.contentWindow, "focus");
+ is(document.activeElement.tagName, "IFRAME", "focus should move to iframe element");
+});
+
+add_task(async function test_iframe_display_none() {
+ // add `display: none` to iframe
+ iframe.style = "display: none;";
+ document.body.offsetWidth;
+
+ // focus input element
+ input.focus();
+ is(document.activeElement.tagName, "INPUT", "focus should move to input element");
+
+ // focus input element in hidden iframe
+ await sendMessage(iframe.contentWindow, "focus");
+ is(document.activeElement.tagName, "INPUT", "focus should stay on input element");
+});
+
+add_task(async function test_remove_iframe_display_none() {
+ // remove `display: none` from iframe
+ iframe.style = "";
+ document.body.offsetWidth;
+
+ // focus input element
+ input.focus();
+ is(document.activeElement.tagName, "INPUT", "focus should move to input element");
+
+ // focus input element in hidden iframe
+ await sendMessage(iframe.contentWindow, "focus");
+ is(document.activeElement.tagName, "IFRAME", "focus should move to iframe element");
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_focus_keyboard_event.html b/dom/base/test/test_focus_keyboard_event.html
new file mode 100644
index 0000000000..3f68516de3
--- /dev/null
+++ b/dom/base/test/test_focus_keyboard_event.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=552255
+-->
+<head>
+<title>Test for bug 552255</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=552255">Mozilla Bug 552255</a>
+<p id="display"></p>
+<input type="text"><br>
+<iframe src="http://example.org/tests/dom/base/test/file_empty.html"></iframe>
+<script>
+add_task(async function cross_origin_iframe() {
+ await SimpleTest.promiseFocus();
+
+ // Setup test in iframe
+ let iframe = document.querySelector("iframe");
+ await SpecialPowers.spawn(iframe, [], () => {
+ content.document.body.addEventListener("keydown", (e) => {
+ ok(false, `should not receive any keydown event, ${e.key}`);
+ });
+ content.addEventListener("focus", (e) => {
+ ok(false, `should not receive any focus event`);
+ });
+ });
+
+ let input = document.querySelector("input");
+ input.focus();
+
+ input.addEventListener("keydown", (e) => {
+ iframe.focus();
+ });
+
+ // Start test.
+ synthesizeKey("a");
+
+ await new Promise(SimpleTest.executeSoon);
+ ok(document.hasFocus(), "document should still have focus");
+ is(document.activeElement, input, "input should still have focus");
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_focus_scroll_padding_tab.html b/dom/base/test/test_focus_scroll_padding_tab.html
new file mode 100644
index 0000000000..1d3b0d3e92
--- /dev/null
+++ b/dom/base/test/test_focus_scroll_padding_tab.html
@@ -0,0 +1,74 @@
+<!doctype html>
+<title>Test for bug 1617342</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<style>
+ :root {
+ scroll-padding: 100px 0;
+ }
+ body {
+ margin: 0;
+ }
+ #fixed-footer {
+ height: 100px;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ background: green;
+ }
+ #fixed-header {
+ height: 100px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ background: green;
+ }
+ .almost-full-padding {
+ height: calc(100vh - 200px);
+ }
+ .padding {
+ height: 100vh;
+ }
+</style>
+<div id="fixed-header"></div>
+<div class="padding"></div>
+<input>
+<div class="almost-full-padding"></div>
+<input>
+<div class="padding"></div>
+<input id="end">
+<div class="padding"></div>
+<div id="fixed-footer"></div>
+<script>
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(async function() {
+ let stack = [];
+ let end = document.getElementById("end");
+
+ let lastActiveElement = document.activeElement;
+
+ do {
+ synthesizeKey("KEY_Tab");
+ is(document.activeElement.tagName, "INPUT", "Should focus inputs only, there's nothing else");
+ isnot(document.activeElement, lastActiveElement, "Focus should've moved once per tab keypress");
+ let rect = document.activeElement.getBoundingClientRect();
+ ok(rect.top >= 100, "Should not be covered by top bar");
+ ok(rect.bottom >= 100, "Should not be covered by bottom bar");
+ lastActiveElement = document.activeElement;
+ stack.push(lastActiveElement);
+ } while (document.activeElement != end)
+
+ do {
+ let previous = stack.pop();
+ let rect = document.activeElement.getBoundingClientRect();
+ ok(rect.top >= 100, "Should not be covered by top bar");
+ ok(rect.bottom >= 100, "Should not be covered by bottom bar");
+ is(document.activeElement, previous, "Focus should've moved backwards as expected");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ } while (stack.length);
+
+ SimpleTest.finish();
+ });
+</script>
diff --git a/dom/base/test/test_focus_scrollable_fieldset.html b/dom/base/test/test_focus_scrollable_fieldset.html
new file mode 100644
index 0000000000..444d078cb1
--- /dev/null
+++ b/dom/base/test/test_focus_scrollable_fieldset.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<title>Test for bug 1351248</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<style>
+ fieldset {
+ overflow: auto;
+ height: 1em;
+ width: 1em;
+ }
+</style>
+<input type="text" id="start">
+
+<fieldset>
+ <input type="text">
+ <input type="text">
+ <input type="text">
+ <input type="text">
+ <input type="text">
+ <input type="text">
+</fieldset>
+
+<input type="text" id="end">
+<script>
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(async function() {
+ // Enable Full Keyboard Access emulation on Mac.
+ if (navigator.platform.indexOf("Mac") === 0) {
+ await SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+ }
+
+ const start = document.getElementById("start");
+
+ start.focus();
+
+ const end = document.getElementById("end");
+
+ is(document.activeElement, start, "Focus moved sanely");
+
+ let lastActiveElement = start;
+ let stack = [start];
+
+ do {
+ synthesizeKey("KEY_Tab");
+ isnot(document.activeElement, lastActiveElement, "Focus should've moved once per tab keypress");
+ lastActiveElement = document.activeElement;
+ stack.push(lastActiveElement);
+ } while (document.activeElement != end)
+
+ is(stack.length, document.querySelectorAll("input").length + 1, "Fieldset should be focusable");
+
+ do {
+ let previous = stack.pop();
+ is(document.activeElement, previous, "Focus should've moved backwards as expected");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ } while (stack.length);
+
+ SimpleTest.finish();
+ });
+</script>
diff --git a/dom/base/test/test_focus_scrollable_input.html b/dom/base/test/test_focus_scrollable_input.html
new file mode 100644
index 0000000000..ca48f3a263
--- /dev/null
+++ b/dom/base/test/test_focus_scrollable_input.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<title>Test for bug 1617342</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<style>
+ input {
+ /* Make them small enough that any value overflows */
+ height: 10px;
+ width: 10px;
+ box-sizing: border-box;
+ font: 16px/1 monospace;
+ }
+</style>
+<input type="text" id="start" value="aaaaaaaaaa">
+
+<input type="text" value="aaaaaaaaaa">
+<input type="number" value="1111">
+<input type="search" value="aaaaaaa">
+<input type="url" value="https://fooooooooooo">
+
+<input type="text" id="end" value="aaaaaaaaaa">
+<script>
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(async function() {
+ // Enable Full Keyboard Access emulation on Mac.
+ if (navigator.platform.indexOf("Mac") === 0) {
+ await SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+ }
+
+ const start = document.getElementById("start");
+
+ start.focus();
+
+ const end = document.getElementById("end");
+
+ is(document.activeElement, start, "Focus moved sanely");
+
+ let lastActiveElement = start;
+ let stack = [start];
+
+ do {
+ synthesizeKey("KEY_Tab");
+ isnot(document.activeElement, lastActiveElement, "Focus should've moved once per tab keypress");
+ lastActiveElement = document.activeElement;
+ stack.push(lastActiveElement);
+ } while (document.activeElement != end)
+
+ do {
+ let previous = stack.pop();
+ is(document.activeElement, previous, "Focus should've moved backwards as expected");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ } while (stack.length);
+
+ SimpleTest.finish();
+ });
+</script>
diff --git a/dom/base/test/test_focus_shadow_dom.html b/dom/base/test/test_focus_shadow_dom.html
new file mode 100644
index 0000000000..3d8899eada
--- /dev/null
+++ b/dom/base/test/test_focus_shadow_dom.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1453693
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1453693</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 1453693 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ async function runTests() {
+ // Enable Full Keyboard Access emulation on Mac.
+ if (navigator.platform.indexOf("Mac") === 0) {
+ await SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+ }
+ win = window.open("file_focus_shadow_dom.html", "", "width=300, height=300");
+ }
+
+ function didRunTests() {
+ setTimeout("SimpleTest.finish()");
+ }
+
+ ;
+
+ </script>
+</head>
+<body onload="SimpleTest.waitForFocus(runTests);">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1453693">Mozilla Bug 1453693</a>
+</body>
+</html>
diff --git a/dom/base/test/test_focus_shadow_dom_root.html b/dom/base/test/test_focus_shadow_dom_root.html
new file mode 100644
index 0000000000..bf51dac3d1
--- /dev/null
+++ b/dom/base/test/test_focus_shadow_dom_root.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<title>Test for bug 1544826</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<div id="host"><a href="#" id="slotted">This is focusable too</a></div>
+<script>
+ const host = document.getElementById("host");
+ const shadow = host.attachShadow({ mode: "open" });
+ shadow.innerHTML = `
+ <a id="shadow-1" href="#">This is focusable</a>
+ <slot></slot>
+ <a id="shadow-2" href="#">So is this</a>
+ `;
+ document.documentElement.remove();
+ document.appendChild(host);
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(async function() {
+ // Enable Full Keyboard Access emulation on Mac.
+ if (navigator.platform.indexOf("Mac") === 0) {
+ await SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+ }
+
+ is(document.documentElement, host, "Host is the document element");
+ host.offsetTop;
+ synthesizeKey("KEY_Tab");
+ is(shadow.activeElement.id, "shadow-1", "First link in Shadow DOM is focused");
+ synthesizeKey("KEY_Tab");
+ is(document.activeElement.id, "slotted", "Slotted link is focused");
+ synthesizeKey("KEY_Tab");
+ is(shadow.activeElement.id, "shadow-2", "Second link in Shadow DOM is focused");
+
+ // Now backwards.
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ is(document.activeElement.id, "slotted", "Backwards: Slotted link is focused");
+ synthesizeKey("KEY_Tab", {shiftKey: true});
+ is(shadow.activeElement.id, "shadow-1", "Backwards: First slotted link is focused");
+
+ SimpleTest.finish();
+ });
+</script>
diff --git a/dom/base/test/test_fragment_sanitization.xhtml b/dom/base/test/test_fragment_sanitization.xhtml
new file mode 100644
index 0000000000..203aebc86f
--- /dev/null
+++ b/dom/base/test/test_fragment_sanitization.xhtml
@@ -0,0 +1,98 @@
+<?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=1432966
+-->
+<window title="Mozilla Bug 1432966"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <script type="application/javascript"><![CDATA[
+
+const NS_HTML = "http://www.w3.org/1999/xhtml";
+
+function awaitLoad(frame) {
+ return new Promise(resolve => {
+ frame.addEventListener("load", resolve, {once: true});
+ });
+}
+
+async function testFrame(frame, html, expected = html) {
+ document.querySelector("body").appendChild(frame);
+ await awaitLoad(frame);
+
+ // Remove the xmlns attributes that will be automatically added when we're
+ // in an XML document, and break the comparison.
+ function unNS(text) {
+ return text.replace(RegExp(` xmlns="${NS_HTML}"`, "g"), "");
+ }
+
+ let doc = frame.contentDocument;
+ let body = doc.body || doc.documentElement;
+
+ let div = doc.createElementNS(NS_HTML, "div");
+ body.appendChild(div);
+
+ div.innerHTML = html;
+ is(unNS(div.innerHTML), expected, "innerHTML value");
+
+ div.innerHTML = "<div></div>";
+ div.firstChild.outerHTML = html;
+ is(unNS(div.innerHTML), expected, "outerHTML value");
+
+ div.textContent = "";
+ div.insertAdjacentHTML("beforeend", html);
+ is(unNS(div.innerHTML), expected, "insertAdjacentHTML('beforeend') value");
+
+ div.innerHTML = "<a>foo</a>";
+ div.firstChild.insertAdjacentHTML("afterend", html);
+ is(unNS(div.innerHTML), "<a>foo</a>" + expected, "insertAdjacentHTML('afterend') value");
+
+ frame.remove();
+}
+
+add_task(async function test_fragment_sanitization() {
+ const XUL_URL = "chrome://global/content/win.xhtml";
+ const HTML_URL = "chrome://mochitests/content/chrome/dom/base/test/file_empty.html";
+
+ const HTML = '<a onclick="foo()" href="javascript:foo"><script>bar()<\/script>Meh.</a><a href="http://foo/"></a>';
+ const SANITIZED = '<a>Meh.</a><a href="http://foo/"></a>';
+
+ info("Test content HTML document");
+ {
+ let frame = document.createElementNS(NS_HTML, "iframe");
+ frame.src = "http://example.com/";
+
+ await testFrame(frame, HTML);
+ }
+
+ info("Test chrome HTML document");
+ {
+ let frame = document.createElementNS(NS_HTML, "iframe");
+ frame.src = HTML_URL;
+
+ await testFrame(frame, HTML, SANITIZED);
+ }
+
+ info("Test chrome XUL document");
+ {
+ let frame = document.createElementNS(NS_HTML, "iframe");
+ frame.src = XUL_URL;
+
+ await testFrame(frame, HTML, SANITIZED);
+ }
+});
+
+ ]]></script>
+
+ <description style="-moz-user-focus: normal; user-select: text;"><![CDATA[
+ hello
+ world
+ ]]></description>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1432966"
+ target="_blank">Mozilla Bug 1432966</a>
+ </body>
+</window>
diff --git a/dom/base/test/test_getAttribute_after_createAttribute.html b/dom/base/test/test_getAttribute_after_createAttribute.html
new file mode 100644
index 0000000000..5e2f4ec306
--- /dev/null
+++ b/dom/base/test/test_getAttribute_after_createAttribute.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for ...</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ var div = document.createElement("div");
+ var attr = document.createAttribute("FOO");
+ attr.value = "bar";
+ div.setAttributeNode(attr);
+ assert_equals(div.getAttribute("FOO"), "bar");
+}, "getAttribute should be able to get an attribute created via createAttribute");
+</script>
diff --git a/dom/base/test/test_getElementById.html b/dom/base/test/test_getElementById.html
new file mode 100644
index 0000000000..8489917c14
--- /dev/null
+++ b/dom/base/test/test_getElementById.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=933193
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 933193</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=933193">Mozilla Bug 933193</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+
+ /** Test for Bug 933193 **/
+ var kid = document.createElement("span");
+ kid.id = "test";
+ var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+ svg.appendChild(kid);
+ is(svg.getElementById("test"), kid,
+ "Should find the right node when not in the DOM");
+
+ var newKid = document.createElement("span");
+ newKid.id = "test";
+ var newKidParent = document.createElement("span");
+ newKidParent.appendChild(newKid);
+ svg.insertBefore(newKidParent, kid);
+ is(svg.getElementById("test"), newKid,
+ "Should find the first right node when not in the DOM");
+ newKid.remove();
+ is(svg.getElementById("test"), kid,
+ "Should find the right node again when not in the DOM");
+
+ document.body.appendChild(svg);
+ is(svg.getElementById("test"), kid,
+ "Should find the right node when in the DOM");
+
+ is(document.getElementById("test").localName, "pre",
+ "document.getElementById should find the first element in the " +
+ "document with that id");
+
+ var frag = document.createDocumentFragment();
+ is(frag.getElementById("test"), null, "Shouldn't find what does not exist");
+ frag.appendChild(kid);
+ is(frag.getElementById("test"), kid,
+ "Should find the right node in the document fragment");
+ is(svg.getElementById("test"), null,
+ "Shouldn't find the kid since it's gone now");
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_getLastOverWindowPointerLocationInCSSPixels.html b/dom/base/test/test_getLastOverWindowPointerLocationInCSSPixels.html
new file mode 100644
index 0000000000..c1bbf723f6
--- /dev/null
+++ b/dom/base/test/test_getLastOverWindowPointerLocationInCSSPixels.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test for Bug 1778486</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/paint_listener.js"></script>
+<script src="chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+div {
+ width: 50px;
+ height: 50px;
+};
+</style>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1778486">Mozilla Bug 1778486</a>
+<p id="display"></p>
+<div id="target_mouse" style="background: red;"></div>
+<div id="target_touch" style="background: green;"></div>
+<script>
+
+function waitForEvent(aTarget, aEvent) {
+ return new Promise(resolve => {
+ aTarget.addEventListener(aEvent, resolve, { once: true });
+ });
+}
+
+function getLastOverWindowPointerLocationScreenOffset() {
+ let x = {};
+ let y = {};
+ let topWindow = window.browsingContext.topChromeWindow;
+ topWindow.windowUtils.getLastOverWindowPointerLocationInCSSPixels(x, y);
+ return {
+ x: Math.trunc(x.value + topWindow.mozInnerScreenX),
+ y: Math.trunc(y.value + topWindow.mozInnerScreenY),
+ };
+}
+
+function getElementScreenOffsetAtCentral(aElement) {
+ let rect = aElement.getBoundingClientRect();
+ return {
+ x: Math.trunc(rect.width / 2 + rect.left + mozInnerScreenX),
+ y: Math.trunc(rect.height / 2 + rect.top + mozInnerScreenY),
+ };
+}
+
+add_setup(async function() {
+ await SpecialPowers.pushPrefEnv({ set: [["test.events.async.enabled", true]] });
+ await waitUntilApzStable();
+});
+
+/** Test for Bug 1778486 **/
+add_task(async function test_mouse() {
+ let target = document.getElementById("target_mouse");
+ let promise = waitForEvent(target, "click");
+ synthesizeMouseAtCenter(target, {});
+ await promise;
+
+ isDeeply(
+ getLastOverWindowPointerLocationScreenOffset(),
+ getElementScreenOffsetAtCentral(target),
+ "check last pointer location");
+});
+
+add_task(async function test_touch() {
+ let target = document.getElementById("target_touch");
+ let promise = waitForEvent(target, "pointerup");
+ synthesizeTouchAtCenter(target, { type: "touchstart" });
+ synthesizeTouchAtCenter(target, { type: "touchend" });
+ await promise;
+
+ isDeeply(
+ getLastOverWindowPointerLocationScreenOffset(),
+ getElementScreenOffsetAtCentral(target),
+ "check last pointer location");
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_getTranslationNodes.html b/dom/base/test/test_getTranslationNodes.html
new file mode 100644
index 0000000000..aa8b1229da
--- /dev/null
+++ b/dom/base/test/test_getTranslationNodes.html
@@ -0,0 +1,225 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for nsIDOMWindowUtils.getTranslationNodes</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest()">
+<script type="application/javascript">
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+
+
+ function testTranslationRoot(rootNode) {
+ var translationNodes = utils.getTranslationNodes(rootNode);
+
+ var expectedResult = rootNode.getAttribute("expected");
+ var expectedLength = expectedResult.split(" ").length;
+
+ is(translationNodes.length, expectedLength,
+ "Correct number of translation nodes for testcase " + rootNode.id);
+
+ var resultList = [];
+ for (var i = 0; i < translationNodes.length; i++) {
+ var node = translationNodes.item(i).localName;
+ if (translationNodes.isTranslationRootAtIndex(i)) {
+ node += "[root]"
+ }
+ resultList.push(node);
+ }
+
+ is(resultList.length, translationNodes.length,
+ "Correct number of translation nodes for testcase " + rootNode.id);
+
+ is(resultList.join(" "), expectedResult,
+ "Correct list of translation nodes for testcase " + rootNode.id);
+ }
+
+ function runTest() {
+ isnot(utils, null, "nsIDOMWindowUtils");
+
+ var testcases = document.querySelectorAll("div[expected]");
+ for (var testcase of testcases) {
+ testTranslationRoot(testcase);
+ }
+
+ var testiframe = document.getElementById("testiframe");
+ var iframediv = testiframe.contentDocument.querySelector("div");
+ try {
+ var foo = utils.getTranslationNodes(iframediv);
+ ok(false, "Cannot use a node from a different document");
+ } catch (e) {
+ is(e.name, "WrongDocumentError", "Cannot use a node from a different document");
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+</script>
+
+<!-- Test that an inline element inside a root is not a root -->
+<div id="testcase1"
+ expected="div[root] span">
+ <div>
+ lorem ipsum <span>dolor</span> sit amet
+ </div>
+</div>
+
+<!-- Test that a usually inline element becomes a root if it is
+ displayed as a block -->
+<div id="testcase2"
+ expected="div[root] span[root]">
+ <div>
+ lorem ipsum <span style="display: block;">dolor</span> sit amet
+ </div>
+</div>
+
+<!-- Test that the content-less <div> is ignored and only the
+ <p> with content is returned -->
+<div id="testcase3"
+ expected="p[root]">
+ <div>
+ <p>lorem ipsum</p>
+ </div>
+</div>
+
+<!-- Test that an inline element which the parent is not a root
+ becomes a root -->
+<div id="testcase4"
+ expected="span[root]">
+ <div>
+ <span>lorem ipsum</span>
+ </div>
+</div>
+
+<!-- Test siblings -->
+<div id="testcase5"
+ expected="li[root] li[root]">
+ <ul>
+ <li>lorem</li>
+ <li>ipsum</li>
+ </ul>
+</div>
+
+<!-- Test <ul> with content outside li -->
+<div id="testcase6"
+ expected="ul[root] li[root] li[root]">
+ <ul>Lorem
+ <li>lorem</li>
+ <li>ipsum</li>
+ </ul>
+</div>
+
+<!-- Test inline siblings -->
+<div id="testcase7"
+ expected="ul[root] li li">
+ <ul>Lorem
+ <li style="display: inline">lorem</li>
+ <li style="display: inline">ipsum</li>
+ </ul>
+</div>
+
+<!-- Test inline siblings becoming roots -->
+<div id="testcase8"
+ expected="li[root] li[root]">
+ <ul>
+ <li style="display: inline">lorem</li>
+ <li style="display: inline">ipsum</li>
+ </ul>
+</div>
+
+<!-- Test that nodes with only punctuation, whitespace
+ or numbers are ignored -->
+<div id="testcase9"
+ expected="li[root] li[root]">
+ <ul>
+ <li>lorem</li>
+ <li>ipsum</li>
+ <li>-.,;'/!@#$%^*()</li>
+ <li>0123456789</li>
+ <li>
+ </li>
+ </ul>
+</div>
+
+<!-- Test paragraphs -->
+<div id="testcase10"
+ expected="p[root] a b p[root] a b">
+ <p>Lorem ipsum <a href="a.htm">dolor</a> sit <b>amet</b>, consetetur</p>
+ <p>Lorem ipsum <a href="a.htm">dolor</a> sit <b>amet</b>, consetetur</p>
+</div>
+
+<!-- Test that a display:none element is not ignored -->
+<div id="testcase11"
+ expected="p[root] a b">
+ <p>Lorem ipsum <a href="a.htm">dolor</a> sit <b style="display:none">amet</b>, consetetur</p>
+</div>
+
+<!-- Test that deep nesting does not cause useless content to be returned -->
+<div id="testcase12"
+ expected="p[root]">
+ <div>
+ <div>
+ <div>
+ <p>Lorem ipsum</p>
+ </div>
+ </div>
+ </div>
+</div>
+
+<!-- Test that deep nesting does not cause useless content to be returned -->
+<div id="testcase13"
+ expected="div[root] p[root]">
+ <div>Lorem ipsum
+ <div>
+ <div>
+ <p>Lorem ipsum</p>
+ </div>
+ </div>
+ </div>
+</div>
+
+<!-- Test that non-html elements and elements that usually have non-translatable
+ content are ignored -->
+<div id="testcase14"
+ expected="div[root]">
+ <div>
+ Lorem Ipsum
+ <noscript>Lorem Ipsum</noscript>
+ <style>.dummyClass { color: blue; }</style>
+ <script> /* script tag */ </script>
+ <code> code </code>
+ <iframe id="testiframe"
+ srcdoc="<div>Lorem ipsum</div>">
+ </iframe>
+ <svg>lorem</svg>
+ <math>ipsum</math>
+ </div>
+</div>
+
+<!-- Test that nesting of inline elements won't produce roots as long as
+ the parents are in the list of translation nodes -->
+<div id="testcase15"
+ expected="p[root] a b span em">
+ <p>Lorem <a>ipsum <b>dolor <span>sit</span> amet</b></a>, <em>consetetur</em></p>
+</div>
+
+<!-- Test that comment nodes are not considered for translation -->
+<div id="testcase16"
+ expected="p[root] p[root]">
+ <p>Lorem ipsum</p>
+ <div> <!-- Comment --> </div>
+ <p>Lorem ipsum</p>
+</div>
+
+<!-- Test that comment nodes are not considered for translation -->
+<div id="testcase17"
+ expected="p[root]">
+ <div>
+ <!-- Comment -->
+ <p>Lorem Ipsum</p>
+ </div>
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_getTranslationNodes_limit.html b/dom/base/test/test_getTranslationNodes_limit.html
new file mode 100644
index 0000000000..b6a89d03d7
--- /dev/null
+++ b/dom/base/test/test_getTranslationNodes_limit.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for nsIDOMWindowUtils.getTranslationNodes</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest()">
+<script type="application/javascript">
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+
+ function runTest() {
+ isnot(utils, null, "nsIDOMWindowUtils");
+
+ for (var i = 0; i < 16000; i++) {
+ var text = document.createTextNode("a");
+ var node = document.createElement("b");
+ node.appendChild(text);
+ document.body.appendChild(node);
+ }
+
+ var translationRoots = utils.getTranslationNodes(document.body);
+ is (translationRoots.length, 15000, "Translation nodes were limited to 15000 nodes.");
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_gsp-qualified.html b/dom/base/test/test_gsp-qualified.html
new file mode 100644
index 0000000000..48504399e1
--- /dev/null
+++ b/dom/base/test/test_gsp-qualified.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=799875
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 799875</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=799875">Mozilla Bug 799875</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe srcdoc="<div id='test2'>"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 799875 **/
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function() {
+ is(window.test, document.getElementById("test"),
+ "Global scope polluter should map ids even when qualified")
+ isnot(document.getElementById("test"), null,
+ "Should have element");
+ is(window[0].test2, window[0].document.getElementById("test2"),
+ "Global scope polluter should map ids across globals");
+ isnot(window[0].document.getElementById("test2"), null,
+ "Should have element in subframe");
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_gsp-quirks.html b/dom/base/test/test_gsp-quirks.html
new file mode 100644
index 0000000000..68c0ab88d1
--- /dev/null
+++ b/dom/base/test/test_gsp-quirks.html
@@ -0,0 +1,27 @@
+<!-- Purposefully in quirks mode -->
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=622491
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 622491</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=622491">Mozilla Bug 622491</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 622491 **/
+is(test, document.getElementById("test"), "Global scope polluter should map ids")
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_gsp-standards.html b/dom/base/test/test_gsp-standards.html
new file mode 100644
index 0000000000..e7d4d88e21
--- /dev/null
+++ b/dom/base/test/test_gsp-standards.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=622491
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 622491</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=622491">Mozilla Bug 622491</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 622491 **/
+is(test, document.getElementById("test"), "Global scope polluter should map ids")
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_history_document_open.html b/dom/base/test/test_history_document_open.html
new file mode 100644
index 0000000000..be782d98e4
--- /dev/null
+++ b/dom/base/test/test_history_document_open.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=943418
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 943418</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 943418 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function continueTest(f) {
+ // Make sure we're the entry script so errors get reported here
+ setTimeout(finishTest, 0, f);
+ }
+
+ function finishTest(f) {
+ f();
+ ok(true, "Got here");
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=943418">Mozilla Bug 943418</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe src="file_history_document_open.html"></script>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_history_state_null.html b/dom/base/test/test_history_state_null.html
new file mode 100644
index 0000000000..d730c5586f
--- /dev/null
+++ b/dom/base/test/test_history_state_null.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=949471
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 949471</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 949471 **/
+ is(history.state, null, "history.state should be null by default");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=949471">Mozilla Bug 949471</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_html_colors_quirks.html b/dom/base/test/test_html_colors_quirks.html
new file mode 100644
index 0000000000..128c2f8b99
--- /dev/null
+++ b/dom/base/test/test_html_colors_quirks.html
@@ -0,0 +1,711 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=121738
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 121738</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=121738">Mozilla Bug 121738</a>
+<table id="table0"></table>
+<table id="table1"></table>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 121738 **/
+
+String.prototype.toAsciiLowerCase = function () {
+ var output = "";
+ for (var i = 0, len = this.length; i < len; ++i) {
+ if (this.charCodeAt(i) >= 0x41 && this.charCodeAt(i) <= 0x5A) {
+ output += String.fromCharCode(this.charCodeAt(i) + 0x20)
+ } else {
+ output += this.charAt(i);
+ }
+ }
+ return output;
+}
+
+var tests = [
+"#135",
+" #135",
+"#135 ",
+" #135 ",
+"# 135",
+"# 135",
+"#123456",
+" #123456",
+"#123456 ",
+" #123456 ",
+"# 123456",
+"# 123456",
+"aliceblue",
+"ALICEBLUE",
+"alıceblue",
+"alÄ°ceblue",
+" aliceblue",
+"aliceblue ",
+" aliceblue ",
+"antiquewhite",
+"aqua",
+"aquamarine",
+"azure",
+"beige",
+"bisque",
+"black",
+"blanchedalmond",
+"blue",
+"blueviolet",
+"brown",
+"burlywood",
+"cadetblue",
+"chartreuse",
+"chocolate",
+"coral",
+"cornflowerblue",
+"cornsilk",
+"crimson",
+"cyan",
+"darkblue",
+"darkcyan",
+"darkgoldenrod",
+"darkgray",
+"darkgreen",
+"darkgrey",
+"darkkhaki",
+"darkmagenta",
+"darkolivegreen",
+"darkorange",
+"darkorchid",
+"darkred",
+"darksalmon",
+"darkseagreen",
+"darkslateblue",
+"darkslategray",
+"darkslategrey",
+"darkturquoise",
+"darkviolet",
+"deeppink",
+"deepskyblue",
+"dimgray",
+"dimgrey",
+"dodgerblue",
+"firebrick",
+"floralwhite",
+"forestgreen",
+"fuchsia",
+"gainsboro",
+"ghostwhite",
+"gold",
+"goldenrod",
+"gray",
+"green",
+"greenyellow",
+"grey",
+"honeydew",
+"hotpink",
+"indianred",
+"indigo",
+"ivory",
+"khaki",
+"lavender",
+"lavenderblush",
+"lawngreen",
+"lemonchiffon",
+"lightblue",
+"lightcoral",
+"lightcyan",
+"lightgoldenrodyellow",
+"lightgray",
+"lightgreen",
+"lightgrey",
+"lightpink",
+"lightsalmon",
+"lightseagreen",
+"lightskyblue",
+"lightslategray",
+"lightslategrey",
+"lightsteelblue",
+"lightyellow",
+"lime",
+"limegreen",
+"linen",
+"magenta",
+"maroon",
+"mediumaquamarine",
+"mediumblue",
+"mediumorchid",
+"mediumpurple",
+"mediumseagreen",
+"mediumslateblue",
+"mediumspringgreen",
+"mediumturquoise",
+"mediumvioletred",
+"midnightblue",
+"mintcream",
+"mistyrose",
+"moccasin",
+"navajowhite",
+"navy",
+"oldlace",
+"olive",
+"olivedrab",
+"orange",
+"orangered",
+"orchid",
+"palegoldenrod",
+"palegreen",
+"paleturquoise",
+"palevioletred",
+"papayawhip",
+"peachpuff",
+"peru",
+"pink",
+"plum",
+"powderblue",
+"purple",
+"red",
+"rosybrown",
+"royalblue",
+"saddlebrown",
+"salmon",
+"sandybrown",
+"seagreen",
+"seashell",
+"sienna",
+"silver",
+"skyblue",
+"slateblue",
+"slategray",
+"slategrey",
+"snow",
+"springgreen",
+"steelblue",
+"tan",
+"teal",
+"thistle",
+"tomato",
+"turquoise",
+"violet",
+"wheat",
+"white",
+"whitesmoke",
+"yellow",
+"yellowgreen",
+"transparent",
+"TRANSPARENT",
+"",
+"inherit",
+"INHERIT",
+"KQ@m?-ldxNK{zH+(FL_owz>YNH^]",
+"aj9c)r+J&3)0E,- Lzv6K6nT@6?I}BY^\\g",
+"Cf}qJN|3D>m:^[7B*fhu>lC[B3\"T_-F",
+"h<s1pMd-8H[,\\caWH1oW3%M",
+"z{y]VZj)%)ZV<OTbO9\\Nbc|YL}4BI<DlUBk$EV`EbN}x/@SDN0(",
+"PSX2Ol8@",
+"d+gYXKUM'&D'S]o<9T\\:hj_i!|l!)e6R4Bo)-(965rlK\"K01C68pgkJ] fx?kjT.O&sY4",
+"[4\"tk)a/v17?0W!F`AyI[='2~;:DF6I>_<O$ he213u",
+"F|r9T&N69MWq3Jrj6",
+"dYR7}n&:Rq[J",
+"M;Z]r@(R([6aT`<sN?uO'2Kb~3U\\\\tQUDxLN1f/D(,Q0w|K;,t`,tQ~[W/c!uQg)d|:D\\U33!DK&d*C`Zc'U#",
+"kV)DKUb~h{SQCM;T*g2!Rj?>Sl=jY;3W9M{Fliu!=>tDY]5",
+"y>X\\kKN|~=J+7Pqp|%9R!nZ,@>mUW9<o;|02LV<fxihsBSKVaTdcae",
+"Q>jc|/:#qwzHL`lL%e~DbhQ+d^tpf9sx%o)jC1Nm}`G;rT2jo+M$=$?BC'|O^]hW^BBo_J->bWG1",
+"OIxA\\5HB7g3Rv;PD)z?jGe?<x`4~9&D9dSDP=ilUauI'qb",
+"aND[Al/^#;n'|V\"Vl$bh5\\G#{%y4#\\W0:ZgXe73ZuXrWcL4gr|B7,ijZZi{p)M+R9{C/&249G",
+"7xK-d6Tx]BU|T,DY.qCwusmV%Ksset",
+"I=UwM''S",
+"w|_;Qw(R:>Clf[#3JFr_+?'1D&}WaY_xaRyTpwio>C;Pjf/kIW{]KK:R&ARiP=_g_UqRVvFKG(OQo6y'wF]Fc",
+"G:",
+"+XZ%s7L3FmGFn]Y!J;.vpAUoGU,&WY8eQeGWW?Jq7ANeM}[?gsV) H\\@{8z_t$oS(_jSq]|9?W*sG%' (d%",
+"*P\"?'?NHA \\!{.S=+LD8Ltr^'=,$4uQ=tVL/T_b6m!PJ8*s*v`;6kp(+8i.}T!9p6{",
+"_@(w<\\DjMk c8/\"/ifJNT_2R>V'}{&72C2+7otvd,$M@Yqc)L=O.muEp28m&AY",
+"J!M#$z|n:+:6@7n*v)UCbkVp0;\"1#}o:i4B9oh=%'I",
+"0",
+"Krq?xAul2cRe&`*Fg2)bV/r>oJ`Z(ae,z%+`E@VkWH&`-jMZ<UW~jxDek;^j2\\Uq;C,Ss",
+"#b\\l~=y5H=#Jy(6FwH5]jU;6D",
+"YO|tw;`E_'G<d~juVPCla%K]q x\"oA-aW|Y@P$_$",
+"}rI\\5x724b29MEauSSX&!AT[J1ce?,rtLAA8X",
+"hlo8jd$D-dI=I#Be:BATkZPR~%Vfe0g_Xw^+wwhHQhC1;sn+P<b&J:~HfxVBX}9b/#HHPS",
+"+#[?UFGUVFn0Zn7yE#TEo{FV\\{6*+s+a=fR",
+"lhv.f!ENs~)?5)z:1^i@BQ|ol}9Cnkw&yV.PPx |y]@,?IL]0L_# b1'wl-]",
+"&DhZ!g%v.sF}4NoP~4<vKpaM0[12!2K!ziYC3`505I*D*J6k\\skbXJ}44J#4y2",
+"oK][N&iIV\"AEs3rIT-::L3&J^Sn42_J2yL= 2xI4o!b\"#2JiAt=",
+"^c;C^{0wD%|y~Z1X'z\\o^gI8L=@2^p3g/L6G?]Nuif;Zf15dF`IPt8",
+"62t-!*`U\\l%BFxi5B~[^~G!}h]DtXrd}y}af3",
+"?N5d9ydHPi?IhwU=41'",
+"GSZeLtA3YahI@oLy/6vT_[B`[PRZ1^.(n8`,8TyqVoCzMd!=9 e",
+"Yck5`_#NgS",
+"K9?z&o",
+"Isl2>%RB8T+,9?B{~A2{fEb[%",
+"&fV(`<ha/(T7J&X\\{YHt+5 =>%SaJ&W0_j]]\"",
+">!sQ/IYU\"Ikc\\ei;HlCcVJ\":G2/m]h1,GvOmxFOOvTUHjHu:LWE\"QU=) ",
+"7Fyx#>\"(\"N",
+"MO6\"Hd2H]r8BJ}z)%J18b<VZ5lrhI",
+"BGQ|tqdwj4};#x@?%ka[`DwgFWg*J+q/}]-\\\\-y#T",
+"zZ=JrTPxh}.(%frt58Cy=C4(*,4]:Gnz5(~iv4@u4re~6yp:zbU0(o.S+qd9eB]A5",
+"n]V3}^{9O<0cO\"rtglDO4Wc)_7Nu_JnK2EBbzRMV3b.Mj\"$9#,+-T\"N=7iPdD F<9_YWw3ZN*V;??*8VN8z?^MXi",
+"fGRSl*i>^*uy|c;5B}tKXu>5hZX:>CB{oWIrxE8@B/f{:u9]:bLO0/ZWeHoNfCc|kSh{/fXs9Y:UKaJ95vFFtB2Y",
+".&-4UOcxR\"Tbgc--@& hoUavCcQW^^fT}:I(d%o}J2t*BRA1{YGXB9>AYu^Bv#rEu`pN65_-r.IQD.?Cc/B({YtK[2KMmVOC3*2J",
+"H3<MOq'81C#\\nUjQc xlsF@c2R<e);T~G]^N0_*M<j!jub~k,mgZ(.>GERhwS;kmmKC?1l} qQ&zcXK?g)S OmF^=E^TlTC)/",
+"8\\5tFz:sod",
+"ILUc5c!'K.7.P&=S,pSYB{",
+"%\\(6.jC\"C4\\2{TYdx,Ln^",
+"tL3HnWq q!'k!#R@2bkvIAI]hk)64-i?uk]oK(nQiKg$`m6tx|#l>m1bEK^&.X[o'b\"\\',A16n>9ZAPI9>",
+"{#Mn0,S~a\"!gw",
+"dv+6'7Dd)fz",
+"9o1*Q:{6#3f uHx\"_",
+".43_zr}X+BtruMV!H!xw 8!9I_}zlBT3W52)rh,9ngeu0o[V_s*z'8x9*yjF!",
+"y3Nm`>P:seF'V'?+<={oU5QQ",
+".#Os_jv,\"@-zsY8j'POOYnY?0ONn?i#d4tqp?~.OF#VC.=<t<+feuf{#@O7lXC@+#t_uKGue%Dk9z",
+"0Ep=zwydU-V<)9<9\\`[4,d^B&Gbo#'HTSEC;qU&1| ocNd69#{nbmYJMlj6Mfs3`w&pc(poie *ZOJIp7%}cVnfml",
+"746}e(rye4lT7#B.Or8j1->Xs@o8f0}/e>uvvkNS[3UC2F]#[>^f74jxoo&9{^ED#,CV\"k'0|xI",
+".D1{.:9gHW}]36RlUQ?!-\"0dn:+(/e@b)|'B",
+"!Nh9xY2y?5ku5f}%]JWw~OfeYdcgI#It` T)3VzYl5gChve[I'rEqyJ \"@(z.Y%fEJ:9k(",
+"J^$^L8:qI=yrerd0kxJBEwby6[>9[) NpqN%)h",
+"l&\\K{s9]aL(,dX?B\"1g1*@9BY~=UO+AWvVRI;ar4p8Tsy~Qk-=x(yp38:j|g'5H~e4",
+"(]Pe,1fTS_P%[xY96#,rwQz=P?z",
+")PC#?b'&|maJBt.6Izz%vV5e!9Sy|G!*Q",
+"pzAG^@/J&)Dc}GP*xO]ezW:*PV|Dt^fF<8GgF_1i=A\"@>nt?yOa|zS<8`/;uY~^ozjvX!K#%us!>2IYITh]Zy<^dq?&\"nqV]ZdZ",
+"T<xz*/H&}36<(4E^/Z1m<#_G0R:=qX?1`*6Y&r'SIO]9OR;m5-Zq?PU^jvLKPLW2wPf",
+")CLhmCI%TwB+t:h.@Vp-#({d0W/R_(^f34LC=V)A",
+"yCT_hl%fUL<T&e;ePsT.pJG@|jO,[pN]]Q<Yu=Lp6X6&$Ka#",
+" $4X",
+"rp",
+"t^(*U<Qdi$!vyg5D\"yQZd<K6<Qptsvzi~D}.Uf?P$E>}t8VP^;3Tamv2Z$1<",
+",",
+"EGCXZ_{eqIwfG-o7o\\\"!ZWTPLd,U-k$Cz]%:vNWdo}vDh!ONtM>mMP{/Cg+2<.J\"a*n#Rtnha",
+"LQ3sIr7Q_ wSD7Zzv$-vxr|3P`pas0#Ze/---{PSwJ3{!a*[k'nFgC\"W+@4URi?qJk&Tt@`abNms40#A^XcAt}",
+"^i356'hX\"hKaZGfTZ|C@#}b3LGz1\">qcH{L8{Fs?O5%:EqQWuro_lc=]gWLVR\\~!J\"[>,H",
+"i{*q<O{Dt^n|FY3,FG>WIRqPH.os$9^P=|yA9?P;MOw;VBwZ^>K=\"%J9SBlv%0+o5k73rW!`l_",
+"-PCM&!G~o#Za^s&)qJELr\\P^\\={_xTFp:%@JF.PeRX\\7b8K",
+"V_sFicB+wx5",
+"\"X^\\d}b9.W.2\"O!yAL21\"Ny5:)=Q3*D|TAzzr^0Yflzjdc!p*.yW,B",
+"kZ`wCP>9Bq5S!r!Vi|Uy/C&H[kz/f^{(Z[OGw'S0\"",
+"Jn%1^rUnNB|%=q%^v*bN|I40}#Htn{G!#~CNAN0KvZcB>Ita(,n",
+"-PlhE[^J55Ui",
+"z`h`uQJ{J",
+"eV\\q5Q4o@Y*,IRMcnpqj5>Id\\yBe?pKH3uF&c<c}:E9[uaH$ 8dXCmI+!C'q@PkE<NVRq~GRW<tfyt/i@%dwI&rL",
+"UGzLF+o3)Ezs=nMxqd^\"=q.Ik}Tk2I`X)R8]Zmy/WQp,|]TdbP)5 J+#Hm6SmWtQ+h?.MQ1W#oyp\\F,'JL>rLtjiHOA",
+"&joOSw7XZVvSt4ZCT*:aq:3ns!v|r);~7gN8'_D",
+"Y<q|Mhn5Nrcb+dR=10pQF5]r@/*7P`79w/htSm2,C~1&sUW{N@v:t9d;HPG&xrI\"YD;V9Y$'g,W'J=GV3,YK",
+"Gx&#{;]l/?[{SyX`kTeo",
+"30PU7@<'58.hRWsJTa9L.hVQ8}7=$}ih4|$Y*9z3[aooT!]}+>b{1JH^.jjEU{,dAXSCbtEh6",
+"%2~x8=A!RW@8N/`hQz`)gl}1DOU9{>Ie'L> 4e]m;kt =isEQ(\\TeI7hWgK-K! p^K'\":3;dxTLO",
+"\\ ):{Woay[4",
+"\\{Ih&}*8^x6@`V@DZB`rSuhYm4i@TW^t9Hx[^`IVumjXc1vA\"~wt8^Jf:US6Z\\xaS&",
+"lo $6<EP|=gAEpd\\M6YDg\"*0m",
+/*
+"ActiveBorder",
+"ActiveCaption",
+"AppWorkspace",
+"Background",
+"ButtonFace",
+"ButtonHighlight",
+"ButtonShadow",
+"ButtonText",
+"CaptionText",
+"GrayText",
+"Highlight",
+"HighlightText",
+"InactiveBorder",
+"InactiveCaption",
+"InactiveCaptionText",
+"InfoBackground",
+"InfoText",
+"Menu",
+"MenuText",
+"Scrollbar",
+"ThreeDDarkShadow",
+"ThreeDFace",
+"ThreeDHighlight",
+"ThreeDLightShadow",
+"ThreeDShadow",
+"Window",
+"WindowFrame",
+"WindowText",
+*/
+"currentColor",
+"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"#",
+"#1",
+"#12",
+"#123",
+"#1234",
+"#12x",
+"abc",
+"123",
+"#0ab0cd0ef",
+"#0ab0cd0e",
+"#0ab0cd0",
+"#0ab0cdaef",
+"#0ab0cdae",
+"#0ab0cda"
+];
+
+var references = [
+"#113355",
+"#001350",
+"#135000",
+"#001350",
+"#013500",
+"#000135",
+"#123456",
+"#002356",
+"#124500",
+"#002356",
+"#013460",
+"#001245",
+"#f0f8ff",
+"#f0f8ff",
+"#a0ce00",
+"#a0ce00",
+"#0ace0e",
+"#a0ebe0",
+"#00cee0",
+"#faebd7",
+"#00ffff",
+"#7fffd4",
+"#f0ffff",
+"#f5f5dc",
+"#ffe4c4",
+"#000000",
+"#ffebcd",
+"#0000ff",
+"#8a2be2",
+"#a52a2a",
+"#deb887",
+"#5f9ea0",
+"#7fff00",
+"#d2691e",
+"#ff7f50",
+"#6495ed",
+"#fff8dc",
+"#dc143c",
+"#00ffff",
+"#00008b",
+"#008b8b",
+"#b8860b",
+"#a9a9a9",
+"#006400",
+"#a9a9a9",
+"#bdb76b",
+"#8b008b",
+"#556b2f",
+"#ff8c00",
+"#9932cc",
+"#8b0000",
+"#e9967a",
+"#8fbc8f",
+"#483d8b",
+"#2f4f4f",
+"#2f4f4f",
+"#00ced1",
+"#9400d3",
+"#ff1493",
+"#00bfff",
+"#696969",
+"#696969",
+"#1e90ff",
+"#b22222",
+"#fffaf0",
+"#228b22",
+"#ff00ff",
+"#dcdcdc",
+"#f8f8ff",
+"#ffd700",
+"#daa520",
+"#808080",
+"#008000",
+"#adff2f",
+"#808080",
+"#f0fff0",
+"#ff69b4",
+"#cd5c5c",
+"#4b0082",
+"#fffff0",
+"#f0e68c",
+"#e6e6fa",
+"#fff0f5",
+"#7cfc00",
+"#fffacd",
+"#add8e6",
+"#f08080",
+"#e0ffff",
+"#fafad2",
+"#d3d3d3",
+"#90ee90",
+"#d3d3d3",
+"#ffb6c1",
+"#ffa07a",
+"#20b2aa",
+"#87cefa",
+"#778899",
+"#778899",
+"#b0c4de",
+"#ffffe0",
+"#00ff00",
+"#32cd32",
+"#faf0e6",
+"#ff00ff",
+"#800000",
+"#66cdaa",
+"#0000cd",
+"#ba55d3",
+"#9370db",
+"#3cb371",
+"#7b68ee",
+"#00fa9a",
+"#48d1cc",
+"#c71585",
+"#191970",
+"#f5fffa",
+"#ffe4e1",
+"#ffe4b5",
+"#ffdead",
+"#000080",
+"#fdf5e6",
+"#808000",
+"#6b8e23",
+"#ffa500",
+"#ff4500",
+"#da70d6",
+"#eee8aa",
+"#98fb98",
+"#afeeee",
+"#db7093",
+"#ffefd5",
+"#ffdab9",
+"#cd853f",
+"#ffc0cb",
+"#dda0dd",
+"#b0e0e6",
+"#800080",
+"#ff0000",
+"#bc8f8f",
+"#4169e1",
+"#8b4513",
+"#fa8072",
+"#f4a460",
+"#2e8b57",
+"#fff5ee",
+"#a0522d",
+"#c0c0c0",
+"#87ceeb",
+"#6a5acd",
+"#708090",
+"#708090",
+"#fffafa",
+"#00ff7f",
+"#4682b4",
+"#d2b48c",
+"#008080",
+"#d8bfd8",
+"#ff6347",
+"#40e0d0",
+"#ee82ee",
+"#f5deb3",
+"#ffffff",
+"#f5f5f5",
+"#ffff00",
+"#9acd32",
+"transparent",
+"transparent",
+"transparent",
+"#00e000",
+"#00e000",
+"#0df000",
+"#0000b0",
+"#007b30",
+"#008001",
+"#004b00",
+"#002080",
+"#099600",
+"#0120e2",
+"#f00630",
+"#d00000",
+"#200000",
+"#0c00d0",
+"#07900a",
+"#db020b",
+"#7000a0",
+"#b00c02",
+"#d6d000",
+"#000000",
+"#1d00f0",
+"#000000",
+"#a00000",
+"#00b600",
+"#007028",
+"#00b0b9",
+"#000000",
+"#f00000",
+"#b00005",
+"#0ea000",
+"#72000a",
+"#ba0c00",
+"#0fe000",
+"#50000b",
+"#000c44",
+"#ae4202",
+"#00005d",
+"#0000af",
+"#5d0041",
+"#a00000",
+"#c00000",
+"#090000",
+"#0209fe",
+"#a00500",
+"#c0100e",
+"#7f0000",
+"#600000",
+"#d00d00",
+"#0004d9",
+"#c00000",
+"#0500ff",
+"#0000c3",
+"#200000",
+"#80f00d",
+"#0c7000",
+"#00c4d0",
+"#a000a0",
+"#00a000",
+"#d0070f",
+"#900600",
+"#002090",
+"#30ef00",
+"#0000e0",
+"#b000c0",
+"#80c200",
+"#0900e0",
+"#0005e0",
+"#800b00",
+"#b0a000",
+"#e00000",
+"#000690",
+"#d00000",
+"#010020",
+"#0000c0",
+"#000060",
+"#004000",
+"#000000",
+"#000da0",
+"#000000",
+"#00d000",
+"#000fa0",
+"#0c5000",
+"#000030",
+"#a0007b",
+"#00cb05",
+"#023000",
+"#9bc000",
+"#b000b0",
+"#00e055",
+"#000000",
+"#0dc0d0",
+"#20600a",
+"#70a070",
+"#f50000",
+"#0000e0",
+"#a900cb",
+"#0000d0",
+"#000a40",
+"#d00060",
+"#000ad0",
+/*
+"ActiveBorder",
+"ActiveCaption",
+"AppWorkspace",
+"Background",
+"ButtonFace",
+"ButtonHighlight",
+"ButtonShadow",
+"ButtonText",
+"CaptionText",
+"GrayText",
+"Highlight",
+"HighlightText",
+"InactiveBorder",
+"InactiveCaption",
+"InactiveCaptionText",
+"InfoBackground",
+"InfoText",
+"Menu",
+"MenuText",
+"Scrollbar",
+"ThreeDDarkShadow",
+"ThreeDFace",
+"ThreeDHighlight",
+"ThreeDLightShadow",
+"ThreeDShadow",
+"Window",
+"WindowFrame",
+"WindowText",
+*/
+"#c0e000",
+"#0000f0",
+"#000000",
+"#0000f0",
+"#000000",
+"#000000",
+"#010000",
+"#010200",
+"#112233",
+"#123400",
+"#010200",
+"#0a0b0c",
+"#010203",
+"#abcdef",
+"#abcde0",
+"#abcd00",
+"#0a0cae",
+"#0a0cae",
+"#0a0ca0"
+];
+
+var todos = {
+" #135": true,
+"#135 ": true,
+" #135 ": true,
+"# 135": true,
+" #123456": true,
+"#123456 ": true,
+" #123456 ": true,
+"# 123456": true,
+" aliceblue": true,
+"aliceblue ": true,
+" aliceblue ": true,
+"H3<MOq'81C#\\nUjQc xlsF@c2R<e);T~G]^N0_*M<j!jub~k,mgZ(.>GERhwS;kmmKC?1l} qQ&zcXK?g)S OmF^=E^TlTC)/": true,
+" $4X": true,
+"UGzLF+o3)Ezs=nMxqd^\"=q.Ik}Tk2I`X)R8]Zmy/WQp,|]TdbP)5 J+#Hm6SmWtQ+h?.MQ1W#oyp\\F,'JL>rLtjiHOA": true
+};
+
+var table0 = document.getElementById("table0");
+var table1 = document.getElementById("table1");
+var cs0 = document.defaultView.getComputedStyle(table0);
+var cs1 = document.defaultView.getComputedStyle(table1);
+var result;
+var reference;
+var log = "";
+var len = tests.length;
+is(tests.length, references.length, "array length mismatch");
+for (var i = 0; i < len; ++i) {
+ table0.setAttribute("bgColor", tests[i]);
+ table1.style.backgroundColor = references[i];
+ ((tests[i] in todos) ? todo_is : is)(
+ cs0.getPropertyValue("background-color"),
+ cs1.getPropertyValue("background-color"),
+ "html color '" + tests[i] + "' should match '" + references[i] + "'");
+}
+</script>
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_html_colors_standards.html b/dom/base/test/test_html_colors_standards.html
new file mode 100644
index 0000000000..0418f10e48
--- /dev/null
+++ b/dom/base/test/test_html_colors_standards.html
@@ -0,0 +1,712 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=121738
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 121738</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=121738">Mozilla Bug 121738</a>
+<table id="table0"></table>
+<table id="table1"></table>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 121738 **/
+
+String.prototype.toAsciiLowerCase = function () {
+ var output = "";
+ for (var i = 0, len = this.length; i < len; ++i) {
+ if (this.charCodeAt(i) >= 0x41 && this.charCodeAt(i) <= 0x5A) {
+ output += String.fromCharCode(this.charCodeAt(i) + 0x20)
+ } else {
+ output += this.charAt(i);
+ }
+ }
+ return output;
+}
+
+var tests = [
+"#135",
+" #135",
+"#135 ",
+" #135 ",
+"# 135",
+"# 135",
+"#123456",
+" #123456",
+"#123456 ",
+" #123456 ",
+"# 123456",
+"# 123456",
+"aliceblue",
+"ALICEBLUE",
+"alıceblue",
+"alÄ°ceblue",
+" aliceblue",
+"aliceblue ",
+" aliceblue ",
+"antiquewhite",
+"aqua",
+"aquamarine",
+"azure",
+"beige",
+"bisque",
+"black",
+"blanchedalmond",
+"blue",
+"blueviolet",
+"brown",
+"burlywood",
+"cadetblue",
+"chartreuse",
+"chocolate",
+"coral",
+"cornflowerblue",
+"cornsilk",
+"crimson",
+"cyan",
+"darkblue",
+"darkcyan",
+"darkgoldenrod",
+"darkgray",
+"darkgreen",
+"darkgrey",
+"darkkhaki",
+"darkmagenta",
+"darkolivegreen",
+"darkorange",
+"darkorchid",
+"darkred",
+"darksalmon",
+"darkseagreen",
+"darkslateblue",
+"darkslategray",
+"darkslategrey",
+"darkturquoise",
+"darkviolet",
+"deeppink",
+"deepskyblue",
+"dimgray",
+"dimgrey",
+"dodgerblue",
+"firebrick",
+"floralwhite",
+"forestgreen",
+"fuchsia",
+"gainsboro",
+"ghostwhite",
+"gold",
+"goldenrod",
+"gray",
+"green",
+"greenyellow",
+"grey",
+"honeydew",
+"hotpink",
+"indianred",
+"indigo",
+"ivory",
+"khaki",
+"lavender",
+"lavenderblush",
+"lawngreen",
+"lemonchiffon",
+"lightblue",
+"lightcoral",
+"lightcyan",
+"lightgoldenrodyellow",
+"lightgray",
+"lightgreen",
+"lightgrey",
+"lightpink",
+"lightsalmon",
+"lightseagreen",
+"lightskyblue",
+"lightslategray",
+"lightslategrey",
+"lightsteelblue",
+"lightyellow",
+"lime",
+"limegreen",
+"linen",
+"magenta",
+"maroon",
+"mediumaquamarine",
+"mediumblue",
+"mediumorchid",
+"mediumpurple",
+"mediumseagreen",
+"mediumslateblue",
+"mediumspringgreen",
+"mediumturquoise",
+"mediumvioletred",
+"midnightblue",
+"mintcream",
+"mistyrose",
+"moccasin",
+"navajowhite",
+"navy",
+"oldlace",
+"olive",
+"olivedrab",
+"orange",
+"orangered",
+"orchid",
+"palegoldenrod",
+"palegreen",
+"paleturquoise",
+"palevioletred",
+"papayawhip",
+"peachpuff",
+"peru",
+"pink",
+"plum",
+"powderblue",
+"purple",
+"red",
+"rosybrown",
+"royalblue",
+"saddlebrown",
+"salmon",
+"sandybrown",
+"seagreen",
+"seashell",
+"sienna",
+"silver",
+"skyblue",
+"slateblue",
+"slategray",
+"slategrey",
+"snow",
+"springgreen",
+"steelblue",
+"tan",
+"teal",
+"thistle",
+"tomato",
+"turquoise",
+"violet",
+"wheat",
+"white",
+"whitesmoke",
+"yellow",
+"yellowgreen",
+"transparent",
+"TRANSPARENT",
+"",
+"inherit",
+"INHERIT",
+"KQ@m?-ldxNK{zH+(FL_owz>YNH^]",
+"aj9c)r+J&3)0E,- Lzv6K6nT@6?I}BY^\\g",
+"Cf}qJN|3D>m:^[7B*fhu>lC[B3\"T_-F",
+"h<s1pMd-8H[,\\caWH1oW3%M",
+"z{y]VZj)%)ZV<OTbO9\\Nbc|YL}4BI<DlUBk$EV`EbN}x/@SDN0(",
+"PSX2Ol8@",
+"d+gYXKUM'&D'S]o<9T\\:hj_i!|l!)e6R4Bo)-(965rlK\"K01C68pgkJ] fx?kjT.O&sY4",
+"[4\"tk)a/v17?0W!F`AyI[='2~;:DF6I>_<O$ he213u",
+"F|r9T&N69MWq3Jrj6",
+"dYR7}n&:Rq[J",
+"M;Z]r@(R([6aT`<sN?uO'2Kb~3U\\\\tQUDxLN1f/D(,Q0w|K;,t`,tQ~[W/c!uQg)d|:D\\U33!DK&d*C`Zc'U#",
+"kV)DKUb~h{SQCM;T*g2!Rj?>Sl=jY;3W9M{Fliu!=>tDY]5",
+"y>X\\kKN|~=J+7Pqp|%9R!nZ,@>mUW9<o;|02LV<fxihsBSKVaTdcae",
+"Q>jc|/:#qwzHL`lL%e~DbhQ+d^tpf9sx%o)jC1Nm}`G;rT2jo+M$=$?BC'|O^]hW^BBo_J->bWG1",
+"OIxA\\5HB7g3Rv;PD)z?jGe?<x`4~9&D9dSDP=ilUauI'qb",
+"aND[Al/^#;n'|V\"Vl$bh5\\G#{%y4#\\W0:ZgXe73ZuXrWcL4gr|B7,ijZZi{p)M+R9{C/&249G",
+"7xK-d6Tx]BU|T,DY.qCwusmV%Ksset",
+"I=UwM''S",
+"w|_;Qw(R:>Clf[#3JFr_+?'1D&}WaY_xaRyTpwio>C;Pjf/kIW{]KK:R&ARiP=_g_UqRVvFKG(OQo6y'wF]Fc",
+"G:",
+"+XZ%s7L3FmGFn]Y!J;.vpAUoGU,&WY8eQeGWW?Jq7ANeM}[?gsV) H\\@{8z_t$oS(_jSq]|9?W*sG%' (d%",
+"*P\"?'?NHA \\!{.S=+LD8Ltr^'=,$4uQ=tVL/T_b6m!PJ8*s*v`;6kp(+8i.}T!9p6{",
+"_@(w<\\DjMk c8/\"/ifJNT_2R>V'}{&72C2+7otvd,$M@Yqc)L=O.muEp28m&AY",
+"J!M#$z|n:+:6@7n*v)UCbkVp0;\"1#}o:i4B9oh=%'I",
+"0",
+"Krq?xAul2cRe&`*Fg2)bV/r>oJ`Z(ae,z%+`E@VkWH&`-jMZ<UW~jxDek;^j2\\Uq;C,Ss",
+"#b\\l~=y5H=#Jy(6FwH5]jU;6D",
+"YO|tw;`E_'G<d~juVPCla%K]q x\"oA-aW|Y@P$_$",
+"}rI\\5x724b29MEauSSX&!AT[J1ce?,rtLAA8X",
+"hlo8jd$D-dI=I#Be:BATkZPR~%Vfe0g_Xw^+wwhHQhC1;sn+P<b&J:~HfxVBX}9b/#HHPS",
+"+#[?UFGUVFn0Zn7yE#TEo{FV\\{6*+s+a=fR",
+"lhv.f!ENs~)?5)z:1^i@BQ|ol}9Cnkw&yV.PPx |y]@,?IL]0L_# b1'wl-]",
+"&DhZ!g%v.sF}4NoP~4<vKpaM0[12!2K!ziYC3`505I*D*J6k\\skbXJ}44J#4y2",
+"oK][N&iIV\"AEs3rIT-::L3&J^Sn42_J2yL= 2xI4o!b\"#2JiAt=",
+"^c;C^{0wD%|y~Z1X'z\\o^gI8L=@2^p3g/L6G?]Nuif;Zf15dF`IPt8",
+"62t-!*`U\\l%BFxi5B~[^~G!}h]DtXrd}y}af3",
+"?N5d9ydHPi?IhwU=41'",
+"GSZeLtA3YahI@oLy/6vT_[B`[PRZ1^.(n8`,8TyqVoCzMd!=9 e",
+"Yck5`_#NgS",
+"K9?z&o",
+"Isl2>%RB8T+,9?B{~A2{fEb[%",
+"&fV(`<ha/(T7J&X\\{YHt+5 =>%SaJ&W0_j]]\"",
+">!sQ/IYU\"Ikc\\ei;HlCcVJ\":G2/m]h1,GvOmxFOOvTUHjHu:LWE\"QU=) ",
+"7Fyx#>\"(\"N",
+"MO6\"Hd2H]r8BJ}z)%J18b<VZ5lrhI",
+"BGQ|tqdwj4};#x@?%ka[`DwgFWg*J+q/}]-\\\\-y#T",
+"zZ=JrTPxh}.(%frt58Cy=C4(*,4]:Gnz5(~iv4@u4re~6yp:zbU0(o.S+qd9eB]A5",
+"n]V3}^{9O<0cO\"rtglDO4Wc)_7Nu_JnK2EBbzRMV3b.Mj\"$9#,+-T\"N=7iPdD F<9_YWw3ZN*V;??*8VN8z?^MXi",
+"fGRSl*i>^*uy|c;5B}tKXu>5hZX:>CB{oWIrxE8@B/f{:u9]:bLO0/ZWeHoNfCc|kSh{/fXs9Y:UKaJ95vFFtB2Y",
+".&-4UOcxR\"Tbgc--@& hoUavCcQW^^fT}:I(d%o}J2t*BRA1{YGXB9>AYu^Bv#rEu`pN65_-r.IQD.?Cc/B({YtK[2KMmVOC3*2J",
+"H3<MOq'81C#\\nUjQc xlsF@c2R<e);T~G]^N0_*M<j!jub~k,mgZ(.>GERhwS;kmmKC?1l} qQ&zcXK?g)S OmF^=E^TlTC)/",
+"8\\5tFz:sod",
+"ILUc5c!'K.7.P&=S,pSYB{",
+"%\\(6.jC\"C4\\2{TYdx,Ln^",
+"tL3HnWq q!'k!#R@2bkvIAI]hk)64-i?uk]oK(nQiKg$`m6tx|#l>m1bEK^&.X[o'b\"\\',A16n>9ZAPI9>",
+"{#Mn0,S~a\"!gw",
+"dv+6'7Dd)fz",
+"9o1*Q:{6#3f uHx\"_",
+".43_zr}X+BtruMV!H!xw 8!9I_}zlBT3W52)rh,9ngeu0o[V_s*z'8x9*yjF!",
+"y3Nm`>P:seF'V'?+<={oU5QQ",
+".#Os_jv,\"@-zsY8j'POOYnY?0ONn?i#d4tqp?~.OF#VC.=<t<+feuf{#@O7lXC@+#t_uKGue%Dk9z",
+"0Ep=zwydU-V<)9<9\\`[4,d^B&Gbo#'HTSEC;qU&1| ocNd69#{nbmYJMlj6Mfs3`w&pc(poie *ZOJIp7%}cVnfml",
+"746}e(rye4lT7#B.Or8j1->Xs@o8f0}/e>uvvkNS[3UC2F]#[>^f74jxoo&9{^ED#,CV\"k'0|xI",
+".D1{.:9gHW}]36RlUQ?!-\"0dn:+(/e@b)|'B",
+"!Nh9xY2y?5ku5f}%]JWw~OfeYdcgI#It` T)3VzYl5gChve[I'rEqyJ \"@(z.Y%fEJ:9k(",
+"J^$^L8:qI=yrerd0kxJBEwby6[>9[) NpqN%)h",
+"l&\\K{s9]aL(,dX?B\"1g1*@9BY~=UO+AWvVRI;ar4p8Tsy~Qk-=x(yp38:j|g'5H~e4",
+"(]Pe,1fTS_P%[xY96#,rwQz=P?z",
+")PC#?b'&|maJBt.6Izz%vV5e!9Sy|G!*Q",
+"pzAG^@/J&)Dc}GP*xO]ezW:*PV|Dt^fF<8GgF_1i=A\"@>nt?yOa|zS<8`/;uY~^ozjvX!K#%us!>2IYITh]Zy<^dq?&\"nqV]ZdZ",
+"T<xz*/H&}36<(4E^/Z1m<#_G0R:=qX?1`*6Y&r'SIO]9OR;m5-Zq?PU^jvLKPLW2wPf",
+")CLhmCI%TwB+t:h.@Vp-#({d0W/R_(^f34LC=V)A",
+"yCT_hl%fUL<T&e;ePsT.pJG@|jO,[pN]]Q<Yu=Lp6X6&$Ka#",
+" $4X",
+"rp",
+"t^(*U<Qdi$!vyg5D\"yQZd<K6<Qptsvzi~D}.Uf?P$E>}t8VP^;3Tamv2Z$1<",
+",",
+"EGCXZ_{eqIwfG-o7o\\\"!ZWTPLd,U-k$Cz]%:vNWdo}vDh!ONtM>mMP{/Cg+2<.J\"a*n#Rtnha",
+"LQ3sIr7Q_ wSD7Zzv$-vxr|3P`pas0#Ze/---{PSwJ3{!a*[k'nFgC\"W+@4URi?qJk&Tt@`abNms40#A^XcAt}",
+"^i356'hX\"hKaZGfTZ|C@#}b3LGz1\">qcH{L8{Fs?O5%:EqQWuro_lc=]gWLVR\\~!J\"[>,H",
+"i{*q<O{Dt^n|FY3,FG>WIRqPH.os$9^P=|yA9?P;MOw;VBwZ^>K=\"%J9SBlv%0+o5k73rW!`l_",
+"-PCM&!G~o#Za^s&)qJELr\\P^\\={_xTFp:%@JF.PeRX\\7b8K",
+"V_sFicB+wx5",
+"\"X^\\d}b9.W.2\"O!yAL21\"Ny5:)=Q3*D|TAzzr^0Yflzjdc!p*.yW,B",
+"kZ`wCP>9Bq5S!r!Vi|Uy/C&H[kz/f^{(Z[OGw'S0\"",
+"Jn%1^rUnNB|%=q%^v*bN|I40}#Htn{G!#~CNAN0KvZcB>Ita(,n",
+"-PlhE[^J55Ui",
+"z`h`uQJ{J",
+"eV\\q5Q4o@Y*,IRMcnpqj5>Id\\yBe?pKH3uF&c<c}:E9[uaH$ 8dXCmI+!C'q@PkE<NVRq~GRW<tfyt/i@%dwI&rL",
+"UGzLF+o3)Ezs=nMxqd^\"=q.Ik}Tk2I`X)R8]Zmy/WQp,|]TdbP)5 J+#Hm6SmWtQ+h?.MQ1W#oyp\\F,'JL>rLtjiHOA",
+"&joOSw7XZVvSt4ZCT*:aq:3ns!v|r);~7gN8'_D",
+"Y<q|Mhn5Nrcb+dR=10pQF5]r@/*7P`79w/htSm2,C~1&sUW{N@v:t9d;HPG&xrI\"YD;V9Y$'g,W'J=GV3,YK",
+"Gx&#{;]l/?[{SyX`kTeo",
+"30PU7@<'58.hRWsJTa9L.hVQ8}7=$}ih4|$Y*9z3[aooT!]}+>b{1JH^.jjEU{,dAXSCbtEh6",
+"%2~x8=A!RW@8N/`hQz`)gl}1DOU9{>Ie'L> 4e]m;kt =isEQ(\\TeI7hWgK-K! p^K'\":3;dxTLO",
+"\\ ):{Woay[4",
+"\\{Ih&}*8^x6@`V@DZB`rSuhYm4i@TW^t9Hx[^`IVumjXc1vA\"~wt8^Jf:US6Z\\xaS&",
+"lo $6<EP|=gAEpd\\M6YDg\"*0m",
+/*
+"ActiveBorder",
+"ActiveCaption",
+"AppWorkspace",
+"Background",
+"ButtonFace",
+"ButtonHighlight",
+"ButtonShadow",
+"ButtonText",
+"CaptionText",
+"GrayText",
+"Highlight",
+"HighlightText",
+"InactiveBorder",
+"InactiveCaption",
+"InactiveCaptionText",
+"InfoBackground",
+"InfoText",
+"Menu",
+"MenuText",
+"Scrollbar",
+"ThreeDDarkShadow",
+"ThreeDFace",
+"ThreeDHighlight",
+"ThreeDLightShadow",
+"ThreeDShadow",
+"Window",
+"WindowFrame",
+"WindowText",
+*/
+"currentColor",
+"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f",
+"#",
+"#1",
+"#12",
+"#123",
+"#1234",
+"#12x",
+"abc",
+"123",
+"#0ab0cd0ef",
+"#0ab0cd0e",
+"#0ab0cd0",
+"#0ab0cdaef",
+"#0ab0cdae",
+"#0ab0cda"
+];
+
+var references = [
+"#113355",
+"#001350",
+"#135000",
+"#001350",
+"#013500",
+"#000135",
+"#123456",
+"#002356",
+"#124500",
+"#002356",
+"#013460",
+"#001245",
+"#f0f8ff",
+"#f0f8ff",
+"#a0ce00",
+"#a0ce00",
+"#0ace0e",
+"#a0ebe0",
+"#00cee0",
+"#faebd7",
+"#00ffff",
+"#7fffd4",
+"#f0ffff",
+"#f5f5dc",
+"#ffe4c4",
+"#000000",
+"#ffebcd",
+"#0000ff",
+"#8a2be2",
+"#a52a2a",
+"#deb887",
+"#5f9ea0",
+"#7fff00",
+"#d2691e",
+"#ff7f50",
+"#6495ed",
+"#fff8dc",
+"#dc143c",
+"#00ffff",
+"#00008b",
+"#008b8b",
+"#b8860b",
+"#a9a9a9",
+"#006400",
+"#a9a9a9",
+"#bdb76b",
+"#8b008b",
+"#556b2f",
+"#ff8c00",
+"#9932cc",
+"#8b0000",
+"#e9967a",
+"#8fbc8f",
+"#483d8b",
+"#2f4f4f",
+"#2f4f4f",
+"#00ced1",
+"#9400d3",
+"#ff1493",
+"#00bfff",
+"#696969",
+"#696969",
+"#1e90ff",
+"#b22222",
+"#fffaf0",
+"#228b22",
+"#ff00ff",
+"#dcdcdc",
+"#f8f8ff",
+"#ffd700",
+"#daa520",
+"#808080",
+"#008000",
+"#adff2f",
+"#808080",
+"#f0fff0",
+"#ff69b4",
+"#cd5c5c",
+"#4b0082",
+"#fffff0",
+"#f0e68c",
+"#e6e6fa",
+"#fff0f5",
+"#7cfc00",
+"#fffacd",
+"#add8e6",
+"#f08080",
+"#e0ffff",
+"#fafad2",
+"#d3d3d3",
+"#90ee90",
+"#d3d3d3",
+"#ffb6c1",
+"#ffa07a",
+"#20b2aa",
+"#87cefa",
+"#778899",
+"#778899",
+"#b0c4de",
+"#ffffe0",
+"#00ff00",
+"#32cd32",
+"#faf0e6",
+"#ff00ff",
+"#800000",
+"#66cdaa",
+"#0000cd",
+"#ba55d3",
+"#9370db",
+"#3cb371",
+"#7b68ee",
+"#00fa9a",
+"#48d1cc",
+"#c71585",
+"#191970",
+"#f5fffa",
+"#ffe4e1",
+"#ffe4b5",
+"#ffdead",
+"#000080",
+"#fdf5e6",
+"#808000",
+"#6b8e23",
+"#ffa500",
+"#ff4500",
+"#da70d6",
+"#eee8aa",
+"#98fb98",
+"#afeeee",
+"#db7093",
+"#ffefd5",
+"#ffdab9",
+"#cd853f",
+"#ffc0cb",
+"#dda0dd",
+"#b0e0e6",
+"#800080",
+"#ff0000",
+"#bc8f8f",
+"#4169e1",
+"#8b4513",
+"#fa8072",
+"#f4a460",
+"#2e8b57",
+"#fff5ee",
+"#a0522d",
+"#c0c0c0",
+"#87ceeb",
+"#6a5acd",
+"#708090",
+"#708090",
+"#fffafa",
+"#00ff7f",
+"#4682b4",
+"#d2b48c",
+"#008080",
+"#d8bfd8",
+"#ff6347",
+"#40e0d0",
+"#ee82ee",
+"#f5deb3",
+"#ffffff",
+"#f5f5f5",
+"#ffff00",
+"#9acd32",
+"transparent",
+"transparent",
+"transparent",
+"#00e000",
+"#00e000",
+"#0df000",
+"#0000b0",
+"#007b30",
+"#008001",
+"#004b00",
+"#002080",
+"#099600",
+"#0120e2",
+"#f00630",
+"#d00000",
+"#200000",
+"#0c00d0",
+"#07900a",
+"#db020b",
+"#7000a0",
+"#b00c02",
+"#d6d000",
+"#000000",
+"#1d00f0",
+"#000000",
+"#a00000",
+"#00b600",
+"#007028",
+"#00b0b9",
+"#000000",
+"#f00000",
+"#b00005",
+"#0ea000",
+"#72000a",
+"#ba0c00",
+"#0fe000",
+"#50000b",
+"#000c44",
+"#ae4202",
+"#00005d",
+"#0000af",
+"#5d0041",
+"#a00000",
+"#c00000",
+"#090000",
+"#0209fe",
+"#a00500",
+"#c0100e",
+"#7f0000",
+"#600000",
+"#d00d00",
+"#0004d9",
+"#c00000",
+"#0500ff",
+"#0000c3",
+"#200000",
+"#80f00d",
+"#0c7000",
+"#00c4d0",
+"#a000a0",
+"#00a000",
+"#d0070f",
+"#900600",
+"#002090",
+"#30ef00",
+"#0000e0",
+"#b000c0",
+"#80c200",
+"#0900e0",
+"#0005e0",
+"#800b00",
+"#b0a000",
+"#e00000",
+"#000690",
+"#d00000",
+"#010020",
+"#0000c0",
+"#000060",
+"#004000",
+"#000000",
+"#000da0",
+"#000000",
+"#00d000",
+"#000fa0",
+"#0c5000",
+"#000030",
+"#a0007b",
+"#00cb05",
+"#023000",
+"#9bc000",
+"#b000b0",
+"#00e055",
+"#000000",
+"#0dc0d0",
+"#20600a",
+"#70a070",
+"#f50000",
+"#0000e0",
+"#a900cb",
+"#0000d0",
+"#000a40",
+"#d00060",
+"#000ad0",
+/*
+"ActiveBorder",
+"ActiveCaption",
+"AppWorkspace",
+"Background",
+"ButtonFace",
+"ButtonHighlight",
+"ButtonShadow",
+"ButtonText",
+"CaptionText",
+"GrayText",
+"Highlight",
+"HighlightText",
+"InactiveBorder",
+"InactiveCaption",
+"InactiveCaptionText",
+"InfoBackground",
+"InfoText",
+"Menu",
+"MenuText",
+"Scrollbar",
+"ThreeDDarkShadow",
+"ThreeDFace",
+"ThreeDHighlight",
+"ThreeDLightShadow",
+"ThreeDShadow",
+"Window",
+"WindowFrame",
+"WindowText",
+*/
+"#c0e000",
+"#0000f0",
+"#000000",
+"#0000f0",
+"#000000",
+"#000000",
+"#010000",
+"#010200",
+"#112233",
+"#123400",
+"#010200",
+"#0a0b0c",
+"#010203",
+"#abcdef",
+"#abcde0",
+"#abcd00",
+"#0a0cae",
+"#0a0cae",
+"#0a0ca0"
+];
+
+var todos = {
+" #135": true,
+"#135 ": true,
+" #135 ": true,
+"# 135": true,
+" #123456": true,
+"#123456 ": true,
+" #123456 ": true,
+"# 123456": true,
+" aliceblue": true,
+"aliceblue ": true,
+" aliceblue ": true,
+"H3<MOq'81C#\\nUjQc xlsF@c2R<e);T~G]^N0_*M<j!jub~k,mgZ(.>GERhwS;kmmKC?1l} qQ&zcXK?g)S OmF^=E^TlTC)/": true,
+" $4X": true,
+"UGzLF+o3)Ezs=nMxqd^\"=q.Ik}Tk2I`X)R8]Zmy/WQp,|]TdbP)5 J+#Hm6SmWtQ+h?.MQ1W#oyp\\F,'JL>rLtjiHOA": true
+};
+
+var table0 = document.getElementById("table0");
+var table1 = document.getElementById("table1");
+var cs0 = document.defaultView.getComputedStyle(table0);
+var cs1 = document.defaultView.getComputedStyle(table1);
+var result;
+var reference;
+var log = "";
+var len = tests.length;
+is(tests.length, references.length, "array length mismatch");
+for (var i = 0; i < len; ++i) {
+ table0.setAttribute("bgColor", tests[i]);
+ table1.style.backgroundColor = references[i];
+ ((tests[i] in todos) ? todo_is : is)(
+ cs0.getPropertyValue("background-color"),
+ cs1.getPropertyValue("background-color"),
+ "html color '" + tests[i] + "' should match '" + references[i] + "'");
+}
+</script>
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_htmlcopyencoder.html b/dom/base/test/test_htmlcopyencoder.html
new file mode 100644
index 0000000000..eecd925f89
--- /dev/null
+++ b/dom/base/test/test_htmlcopyencoder.html
@@ -0,0 +1,195 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Test on the html copy encoder</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=422403">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function testHtmlCopyEncoder () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder;
+ var encoder = SpecialPowers.Cu.createHTMLCopyEncoder();
+ var out, expected;
+
+ var node = document.getElementById('draggable');
+
+
+ // in the following tests, we must use the OutputLFLineBreak flag, to avoid
+ // to have the default line break of the platform in the result, so the test
+ // can pass on all platform
+
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = 'This is a <em>draggable</em> bit of text.';
+ is(out, expected, "test container node ");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>";
+ is(out, expected, "test node");
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = "<div style=\"display: none\">\n\n<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>\n\n</div>";
+ is(out, expected, "test selection");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputAbsoluteLinks | de.OutputEncodeHTMLEntities | de.OutputSelectionOnly | de.OutputRaw);
+ encoder.setSelection(select);
+ var outContext = {value:''}, outInfo = {value:''};
+ out = encoder.encodeToStringWithContext(outContext, outInfo);
+ expected = "<div style=\"display: none\">\n\n<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>\n\n</div>";
+ is(out, expected, "test encodeToStringWithContext with selection ");
+
+ node.nextSibling.data="\nfoo bar\n";
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>";
+ is(out, expected, "test selection with additional data");
+
+ node = document.getElementById('aList');
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id=\"aList\">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = '\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n';
+ is(out, expected, "test list container node");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<ol id=\"aList\">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>";
+ is(out, expected, "test list node");
+
+ var liList = node.getElementsByTagName("li");
+ var range = document.createRange();
+
+ // selection start at the first child of the ol, and end after the element ol
+ range.setStart(node, 1);
+ range.setEnd(node.parentNode, 2);
+ select.removeAllRanges();
+ select.addRange(range);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id="aList">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the first child of the ol, and end after the element ol");
+
+ // selection start at the third child of the ol, and end after the element ol
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id="aList"><li value=\"2\">sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol");
+
+
+ // selection start at the third child of the ol, and end after the element ol + ol start at the value 5
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ node.setAttribute("start","5");
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id=\"aList\" start=\"5\"><li value=\"6\">sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol + ol start at the value 5");
+
+ // selection contains only some child of the ol
+ node.removeAttribute("start");
+ range.setStart(node, 3);
+ range.setEnd(node, 5);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ is(out, expected, "test list selection with range: selection contains only some child of the ol");
+
+ // selection contains only some child of the ol + ol start at the value 5
+ node.setAttribute("start","5");
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ is(out, expected, "test list selection with range: selection contains only some child of the ol + ol start at the value 5");
+
+ // selection contains only some child of the ol + a value is set on the first li
+ node.removeAttribute("start");
+ liList[0].setAttribute("value","8");
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ is(out, expected, "test list selection with range: selection contains only some child of the ol + ol start at the value 5");
+
+ select.selectAllChildren(node);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id=\"aList\">\n <li value=\"8\">Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ is(out, expected, "test list selection with a value on a LI");
+
+ //test Bug 436703
+ node = document.getElementById('aContentEditable');
+ select.selectAllChildren(node);
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<p>one</p><p>two</p>';
+ is(out, expected, "select all children in an contentEditable div should not select the div itself");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlCopyEncoder);
+
+</script>
+</pre>
+<div style="display: none">
+
+<div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> bit of text.</div>
+
+</div>
+<div style="display: none">
+
+<ol id="aList">
+ <li>Lorem ipsum dolor</li>
+ <li>sit amet, <strong>consectetuer</strong> </li>
+ <li>adipiscing elit</li>
+ <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>
+ <li>aptent taciti</li>
+</ol>
+foo bar
+</div>
+
+<div id="aContentEditable" contentEditable="true"><p>one</p><p>two</p></div>
+</body>
+</html>
diff --git a/dom/base/test/test_htmlcopyencoder.xhtml b/dom/base/test/test_htmlcopyencoder.xhtml
new file mode 100644
index 0000000000..8740a54f02
--- /dev/null
+++ b/dom/base/test/test_htmlcopyencoder.xhtml
@@ -0,0 +1,179 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+-->
+<head>
+ <title>Test the html copy encoder with XHTML</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=422403">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//<![CDATA[
+function testHtmlCopyEncoder () {
+ const de = SpecialPowers.Ci.nsIDocumentEncoder;
+ var encoder = SpecialPowers.Cu.createHTMLCopyEncoder();
+ var out, expected;
+
+ var node = document.getElementById('draggable');
+
+
+ // in the following tests, we must use the OutputLFLineBreak flag, to avoid
+ // to have the default line break of the platform in the result, so the test
+ // can pass on all platform
+
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = 'This is a <em>draggable</em> <br>bit of text.';
+ is(out, expected, "test container node ");
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> <br>bit of text.</div>";
+ is(out, expected, "test node");
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = "<div style=\"display: none;\">\n\n<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> <br>bit of text.</div>\n\n</div>";
+ todo_is(out, expected, "test selection");
+
+ node.nextSibling.data="\nfoo bar\n";
+ encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em>\n <br>bit of text.</div>";
+ todo_is(out, expected, "test selection with additional data");
+
+ node = document.getElementById('aList');
+
+ var select = window.getSelection();
+ select.selectAllChildren(node);
+
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id=\"aList\">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus \naliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ todo_is(out, expected, "test list selection");
+
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setContainerNode(node);
+ out = encoder.encodeToString();
+ expected = '\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n';
+ is(out, expected, "test list container node");
+
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setNode(node);
+ out = encoder.encodeToString();
+ expected = "<ol id=\"aList\">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>";
+ is(out, expected, "test list node");
+
+ var liList = node.getElementsByTagName("li");
+ var range = document.createRange();
+
+ // selection start at the first child of the ol, and end after the element ol
+ range.setStart(node, 1);
+ range.setEnd(node.parentNode, 2);
+ select.removeAllRanges();
+ select.addRange(range);
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id="aList">\n <li>Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ todo_is(out, expected, "test list selection with range: selection start at the first child of the ol, and end after the element ol");
+
+ // selection start at the third child of the ol, and end after the element ol
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id="aList"><li value=\"2\">sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ todo_is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol");
+
+
+ // selection start at the third child of the ol, and end after the element ol + ol start at the value 5
+ range.setStart(node, 3);
+ range.setEnd(node.parentNode, 2);
+ node.setAttribute("start","5");
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol start=\"5\" id=\"aList\"><li value=\"6\">sit amet, <strong>consectetuer</strong>\n </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ todo_is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol + ol start at the value 5");
+
+
+ // selection contains only some child of the ol
+ node.removeAttribute("start");
+ range.setStart(node, 3);
+ range.setEnd(node, 5);
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ todo_is(out, expected, "test list selection with range: selection contains only some child of the ol");
+
+ // selection contains only some child of the ol + ol start at the value 5
+ node.setAttribute("start","5");
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ todo_is(out, expected, "test list selection with range: selection contains only some child of the ol + ol start at the value 5");
+
+
+ // selection contains only some child of the ol + a value is set on the first li
+ node.removeAttribute("start");
+ liList[0].setAttribute("value","8");
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<li>sit amet, <strong>consectetuer</strong> </li>\n ';
+ todo_is(out, expected, "test list selection: contains only some child of the ol + a value is set on the first li");
+
+ select.selectAllChildren(node);
+ encoder.init(document, "text/html",de.OutputLFLineBreak | de.OutputSelectionOnly);
+ encoder.setSelection(select);
+ out = encoder.encodeToString();
+ expected = '<ol id=\"aList\">\n <li value=\"8\">Lorem ipsum dolor</li>\n <li>sit amet, <strong>consectetuer</strong> </li>\n <li>adipiscing elit</li>\n <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus \naliquet lectus. Nunc vitae eros. Class</li>\n <li>aptent taciti</li>\n</ol>';
+ todo_is(out, expected, "test list selection with a value on a LI");
+
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(testHtmlCopyEncoder);
+//]]>
+</script>
+</pre>
+<div style="display: none">
+
+<div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> <br/>bit of text.</div>
+
+</div>
+<div style="display: none">
+
+<ol id="aList">
+ <li>Lorem ipsum dolor</li>
+ <li>sit amet, <strong>consectetuer</strong> </li>
+ <li>adipiscing elit</li>
+ <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>
+ <li>aptent taciti</li>
+</ol>
+foo bar
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_iframe_event_listener_leaks.html b/dom/base/test/test_iframe_event_listener_leaks.html
new file mode 100644
index 0000000000..a497730ac6
--- /dev/null
+++ b/dom/base/test/test_iframe_event_listener_leaks.html
@@ -0,0 +1,41 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1451426 - Test iframe event listener leak conditions</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/dom/events/test/event_leak_utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+// Manipulate iframe. Its important here that we create a
+// listener callback from the DOM objects back to the frame's global
+// in order to exercise the leak condition.
+async function useIFrame(contentWindow) {
+ let f = contentWindow.document.createElement("iframe");
+ contentWindow.document.body.appendChild(f);
+ f.onload = _ => {
+ contentWindow.loadCount += 1;
+ };
+}
+
+async function runTest() {
+ try {
+ await checkForEventListenerLeaks("IFrame", useIFrame);
+ } catch (e) {
+ ok(false, e);
+ } finally {
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+addEventListener("load", runTest, { once: true });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_iframe_referrer.html b/dom/base/test/test_iframe_referrer.html
new file mode 100644
index 0000000000..17f0e915e7
--- /dev/null
+++ b/dom/base/test/test_iframe_referrer.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test iframe referrer policy attribute for Bug 1175736</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that iframe referrer attribute is honoured correctly
+ * regular loads
+ * regression tests that meta referrer is still working even if attribute referrers are enabled
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-iframe-policy-test"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "unsafe-url (iframe) with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ DESC: "origin (iframe) with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'no-referrer-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "no-referrer (iframe) with origin in meta",
+ RESULT: 'none'},
+ {NAME: 'no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ DESC: "no-referrer in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'origin-with-no-meta',
+ META_POLICY: '',
+ DESC: "origin (iframe) with no meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "same-origin with origin in meta",
+ RESULT: 'full'},
+
+ // 1. Downgrade.
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin-when-cross-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+
+ // 2. No downgrade.
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'origin in meta strict-origin-when-cross-origin in attr',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'strict-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ DESC: "strict-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ DESC: "same-origin with origin in meta",
+ RESULT: 'none'},
+ ]}
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/test_iframe_referrer_changing.html b/dom/base/test/test_iframe_referrer_changing.html
new file mode 100644
index 0000000000..d3a39480a3
--- /dev/null
+++ b/dom/base/test/test_iframe_referrer_changing.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test iframe referrer policy attribute for Bug 1175736</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that iframe referrer attribute is honoured correctly
+ * testing setAttribute and .referrer
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY"];
+
+ const testCases = [
+ {ACTION: ["generate-iframe-changing-policy-test-set-attribute"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NEW_ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'no-referrer-unsafe-url-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "no-referrer (iframe, orginally unsafe-url) with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-origin-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ DESC: "unsafe-url (iframe, orginally origin) with no-referrer in meta",
+ RESULT: 'full'}]},
+ {ACTION: ["generate-iframe-changing-policy-test-property"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'unsafe-url-no-referrer-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "unsafe-url (iframe, orginally no-referrer) with origin in meta",
+ RESULT: 'full'}]}
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/test_iframe_referrer_invalid.html b/dom/base/test/test_iframe_referrer_invalid.html
new file mode 100644
index 0000000000..8f6ba2126c
--- /dev/null
+++ b/dom/base/test/test_iframe_referrer_invalid.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test iframe referrer policy attribute for Bug 1175736</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that iframe referrer attribute is honoured correctly
+ * invalid referrer policies
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-iframe-policy-test"],
+ TESTS: [
+ // setting invalid refer values -> we expect either full referrer (default)
+ // or whatever is specified in the meta referrer policy
+
+ // Note that for those test cases which require cross-origin test, we use different
+ // scheme to result in cross-origin request.
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-no-meta',
+ META_POLICY: '',
+ DESC: "origin-when-cross-origin (iframe) with no meta",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'default',
+ NAME: 'default-with-no-meta',
+ META_POLICY: '',
+ DESC: "default (iframe) with no meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'something',
+ NAME: 'something-with-no-meta',
+ META_POLICY: '',
+ DESC: "something (iframe) with no meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ DESC: "origin-when-cross-origin (iframe) with no-referrer in meta",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ DESC: "origin-when-cross-origin (iframe) with unsafe-url in meta",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "origin-when-cross-origin (iframe) with origin in meta",
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'origin'},
+ {NAME: 'origin-in-meta',
+ META_POLICY: 'origin',
+ DESC: "origin in meta",
+ RESULT: 'origin'},
+ {NAME: 'no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ DESC: "no-referrer in meta",
+ RESULT: 'none'}]}
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/test_innersize_scrollport.html b/dom/base/test/test_innersize_scrollport.html
new file mode 100644
index 0000000000..c820d3f5d1
--- /dev/null
+++ b/dom/base/test/test_innersize_scrollport.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 919437</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=919437">Mozilla Bug 919437</a>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 919437 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function run()
+{
+ var oldWidth = window.innerWidth;
+ var oldHeight = window.innerHeight;
+ var newWidth = oldWidth / 2;
+ var newHeight = oldHeight / 2;
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.setVisualViewportSize(newWidth, newHeight);
+ is(window.innerWidth, oldWidth, "innerWidth unaffected by changes to visual viewport size");
+ is(window.innerHeight, oldHeight, "innerHeight unaffected by changes to visual viewport size");
+
+ SimpleTest.finish();
+}
+
+window.addEventListener("load", run);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_input_vsync_alignment_inner_event_loop.html b/dom/base/test/test_input_vsync_alignment_inner_event_loop.html
new file mode 100644
index 0000000000..022d06663f
--- /dev/null
+++ b/dom/base/test/test_input_vsync_alignment_inner_event_loop.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <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 />
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ function runTest() {
+ function checkResult() {
+ ok(true, "didn't crash");
+ SimpleTest.finish();
+ }
+
+ // Dispatch an vsync event to the queue
+ window.requestAnimationFrame(() => {
+ window.requestAnimationFrame(() => {
+ });
+ });
+
+ // Dispatch the first input tasks. Since there's a vsync
+ // task in the queue, so this task takes the priority and runs
+ // first.
+ SpecialPowers.Services.tm.dispatchToMainThread(function() {
+ let secondInputRun = false;
+
+ // Dispatch the second input task to the queue.
+ SpecialPowers.Services.tm.dispatchToMainThread(function() {
+ secondInputRun = true;
+ }, SpecialPowers.Ci.nsIRunnablePriority.PRIORITY_INPUT_HIGH);
+
+ // Inner event loop runs and picks the second input task to run.
+ SpecialPowers.Services.tm.spinEventLoopUntil(
+ "Test(vsync_alignment_inner_event_loop.html)", () => secondInputRun);
+
+ setTimeout(checkResult, 0);
+ }, SpecialPowers.Ci.nsIRunnablePriority.PRIORITY_INPUT_HIGH);
+ }
+
+ SpecialPowers.pushPrefEnv({
+ set: [["dom.input_events.strict_input_vsync_alignment", true]]
+ }, runTest());
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_input_vsync_alignment_input_while_vsync.html b/dom/base/test/test_input_vsync_alignment_input_while_vsync.html
new file mode 100644
index 0000000000..6d1ac469fe
--- /dev/null
+++ b/dom/base/test/test_input_vsync_alignment_input_while_vsync.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <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 />
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ function triggerKey() {
+ SpecialPowers.loadChromeScript(() => {
+ /* eslint-env mozilla/chrome-script */
+ var win = Services.wm.getMostRecentBrowserWindow();
+ for (let i = 0; i < 200; ++i) {
+ EventUtils.synthesizeKey("a", {}, win);
+ }
+ });
+ }
+
+ function runTest() {
+ const input = document.querySelector("input");
+ input.focus();
+
+ let didInputRun = false;
+
+ input.addEventListener("input", function() {
+ if (!didInputRun) {
+ didInputRun = true;
+ window.requestAnimationFrame(() => {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "slow.sjs", false);
+ xhr.send();
+ ok(true, "Didn't crash!");
+ SimpleTest.finish();
+ });
+ }
+ });
+
+ triggerKey();
+ }
+ runTest();
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_input_vsync_alignment_lower_than_normal.html b/dom/base/test/test_input_vsync_alignment_lower_than_normal.html
new file mode 100644
index 0000000000..1d06e506b4
--- /dev/null
+++ b/dom/base/test/test_input_vsync_alignment_lower_than_normal.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body >
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ let runOrder = [];
+ function checkResult() {
+ if (runOrder.length == 3) {
+ if (runOrder[0] === "Normal") {
+ isDeeply(
+ runOrder,
+ ["Normal", "InputHigh", "Vsync"],
+ "Input priority tasks should let normal tasks to run first when there's no pending vsync"
+ );
+ SimpleTest.finish();
+ } else {
+ runOrder = [];
+ runTest();
+ }
+ }
+ }
+
+ function runTest() {
+ window.requestAnimationFrame(() => {
+ window.requestAnimationFrame(() => {
+ runOrder.push("Vsync");
+ checkResult();
+ });
+ SpecialPowers.Services.tm.dispatchToMainThread(function() {
+ runOrder.push("InputHigh");
+ checkResult();
+ }, SpecialPowers.Ci.nsIRunnablePriority.PRIORITY_INPUT_HIGH);
+ SpecialPowers.Services.tm.dispatchToMainThread(function() {
+ runOrder.push("Normal");
+ checkResult();
+ }, SpecialPowers.Ci.nsIRunnablePriority.PRIORITY_NORMAL);
+ });
+ }
+
+ SpecialPowers.pushPrefEnv({
+ set: [["dom.input_events.strict_input_vsync_alignment", true]]
+ }, runTest());
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_integer_attr_with_leading_zero.html b/dom/base/test/test_integer_attr_with_leading_zero.html
new file mode 100644
index 0000000000..816fb331c4
--- /dev/null
+++ b/dom/base/test/test_integer_attr_with_leading_zero.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for parsing of integer attributes with leading zero</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var td = document.createElement("td");
+var li = document.createElement("li");
+// Array of tests: "values" are the values to set, "tdreflection" is the
+// corresponding td.rowspan value, "lireflection" is the corresponding li.value
+// value.
+var testData = [
+ {
+ values: [
+ "2",
+ "02",
+ "002",
+ "00002",
+ ],
+ tdreflection: 2,
+ lireflection: 2,
+ },
+ {
+ values: [
+ "-2",
+ "-02",
+ "-002",
+ "-00002",
+ ],
+ tdreflection: 1,
+ lireflection: -2,
+ },
+ {
+ values: [
+ "-0",
+ "-00",
+ "0",
+ "00",
+ ],
+ tdreflection: 0,
+ lireflection: 0,
+ },
+];
+
+for (var data of testData) {
+ for (var value of data.values) {
+ td.setAttribute("rowspan", value);
+ li.setAttribute("value", value);
+ test(function() {
+ assert_equals(td.rowSpan, data.tdreflection);
+ }, `<td> reflection for ${value}`);
+ test(function() {
+ assert_equals(td.getAttribute("rowspan"), value);
+ }, `<td> setAttribute roundtripping for ${value}`);
+ test(function() {
+ assert_equals(li.value, data.lireflection);
+ }, `<li> reflection for ${value}`);
+ test(function() {
+ assert_equals(li.getAttribute("value"), value);
+ }, `<li> setAttribute roundtripping for ${value}`);
+ }
+}
+</script>
diff --git a/dom/base/test/test_intersectionobservers.html b/dom/base/test/test_intersectionobservers.html
new file mode 100644
index 0000000000..97fa173cef
--- /dev/null
+++ b/dom/base/test/test_intersectionobservers.html
@@ -0,0 +1,1221 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1243846
+
+Some tests ported from IntersectionObserver/polyfill/intersection-observer-test.html
+
+Original license header:
+
+Copyright 2016 Google Inc. All Rights Reserved.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1243846</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="onLoad()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1243846">Mozilla Bug 1243846</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+ /* eslint "no-shadow": ["error", {"allow": ["done", "next"]}] */
+ var tests = [];
+ var curDescribeMsg = '';
+ var curItMsg = '';
+
+ function beforeEach_fn() { };
+ function afterEach_fn() { };
+
+ function before(fn) {
+ fn();
+ }
+
+ function beforeEach(fn) {
+ beforeEach_fn = fn;
+ }
+
+ function afterEach(fn) {
+ afterEach_fn = fn;
+ }
+
+ function it(msg, fn) {
+ tests.push({
+ msg: `${msg} [${curDescribeMsg}]`,
+ fn
+ });
+ }
+
+ var callbacks = [];
+ function callDelayed(fn) {
+ callbacks.push(fn);
+ }
+
+ requestAnimationFrame(function tick() {
+ var i = callbacks.length;
+ while (i--) {
+ var cb = callbacks[i];
+ SimpleTest.executeSoon(function() { SimpleTest.executeSoon(cb) });
+ callbacks.splice(i, 1);
+ }
+ requestAnimationFrame(tick);
+ });
+
+ function expect(val) {
+ return {
+ to: {
+ throwException (regexp) {
+ try {
+ val();
+ ok(false, `${curItMsg} - an exception should have beeen thrown`);
+ } catch (e) {
+ ok(regexp.test(e), `${curItMsg} - supplied regexp should match thrown exception`);
+ }
+ },
+ get be() {
+ var fn = function (expected) {
+ is(val, expected, curItMsg);
+ };
+ fn.ok = function () {
+ ok(val, curItMsg);
+ };
+ fn.greaterThan = function (other) {
+ ok(val > other, `${curItMsg} - ${val} should be greater than ${other}`);
+ };
+ fn.lessThan = function (other) {
+ ok(val < other, `${curItMsg} - ${val} should be less than ${other}`);
+ };
+ return fn;
+ },
+ eql (expected) {
+ if (Array.isArray(expected)) {
+ if (!Array.isArray(val)) {
+ ok(false, curItMsg, `${curItMsg} - should be an array,`);
+ return;
+ }
+ is(val.length, expected.length, curItMsg, `${curItMsg} - arrays should be the same length`);
+ if (expected.length != val.length) {
+ return;
+ }
+ for (var i = 0; i < expected.length; i++) {
+ is(val[i], expected[i], `${curItMsg} - array elements at position ${i} should be equal`);
+ if (expected[i] != val[i]) {
+ return;
+ }
+ }
+ ok(true);
+ }
+ },
+ }
+ }
+ }
+
+ function describe(msg, fn) {
+ curDescribeMsg = msg;
+ fn();
+ curDescribeMsg = '';
+ }
+
+ function next() {
+ var test = tests.shift();
+ if (test) {
+ console.log(test.msg);
+ curItMsg = test.msg;
+ var fn = test.fn;
+ beforeEach_fn();
+ if (fn.length) {
+ fn(function () {
+ afterEach_fn();
+ next();
+ });
+ } else {
+ fn();
+ afterEach_fn();
+ next();
+ }
+ } else {
+ SimpleTest.finish();
+ }
+ }
+
+ var sinon = {
+ spy () {
+ var cbs = [];
+ var fn = function () {
+ fn.callCount++;
+ fn.lastCall = { args: arguments };
+ if (cbs.length) {
+ cbs.shift()();
+ }
+ };
+ fn.callCount = 0;
+ fn.lastCall = { args: [] };
+ fn.waitForNotification = (fn1) => {
+ cbs.push(fn1);
+ };
+ return fn;
+ }
+ };
+
+ var ASYNC_TIMEOUT = 300;
+
+
+ var io;
+ var noop = function() {};
+
+
+ // References to DOM elements, which are accessible to any test
+ // and reset prior to each test so state isn't shared.
+ var rootEl;
+ var grandParentEl;
+ var parentEl;
+ var targetEl1;
+ var targetEl2;
+ var targetEl3;
+ var targetEl4;
+ var targetEl5;
+
+
+ describe('IntersectionObserver', function() {
+
+ before(function() {
+
+ });
+
+
+ beforeEach(function() {
+ addStyles();
+ addFixtures();
+ });
+
+
+ afterEach(function() {
+ if (io && 'disconnect' in io) io.disconnect();
+ io = null;
+
+ window.onmessage = null;
+
+ removeStyles();
+ removeFixtures();
+ });
+
+
+ describe('constructor', function() {
+
+ it('throws when callback is not a function', function() {
+ expect(function() {
+ io = new IntersectionObserver(null);
+ }).to.throwException(/.*/i);
+ });
+
+
+ it('instantiates root correctly', function() {
+ io = new IntersectionObserver(noop);
+ expect(io.root).to.be(null);
+
+ io = new IntersectionObserver(noop, {root: rootEl});
+ expect(io.root).to.be(rootEl);
+ });
+
+
+ it('throws when root is not an Element', function() {
+ expect(function() {
+ io = new IntersectionObserver(noop, {root: 'foo'});
+ }).to.throwException(/.*/i);
+ });
+
+
+ it('instantiates rootMargin correctly', function() {
+ io = new IntersectionObserver(noop, {rootMargin: '10px'});
+ expect(io.rootMargin).to.be('10px 10px 10px 10px');
+
+ io = new IntersectionObserver(noop, {rootMargin: '10px -5%'});
+ expect(io.rootMargin).to.be('10px -5% 10px -5%');
+
+ io = new IntersectionObserver(noop, {rootMargin: '10px 20% 0px'});
+ expect(io.rootMargin).to.be('10px 20% 0px 20%');
+
+ io = new IntersectionObserver(noop, {rootMargin: '0px 0px -5% 5px'});
+ expect(io.rootMargin).to.be('0px 0px -5% 5px');
+ });
+
+
+ it('throws when rootMargin is not in pixels or percent', function() {
+ expect(function() {
+ io = new IntersectionObserver(noop, {rootMargin: 'auto'});
+ }).to.throwException(/pixels.*percent/i);
+ });
+
+
+ it('instantiates thresholds correctly', function() {
+ io = new IntersectionObserver(noop);
+ expect(io.thresholds).to.eql([0]);
+
+ io = new IntersectionObserver(noop, {threshold: 0.5});
+ expect(io.thresholds).to.eql([0.5]);
+
+ io = new IntersectionObserver(noop, {threshold: [0.25, 0.5, 0.75]});
+ expect(io.thresholds).to.eql([0.25, 0.5, 0.75]);
+
+ io = new IntersectionObserver(noop, {threshold: [1, .5, 0]});
+ expect(io.thresholds).to.eql([0, .5, 1]);
+ });
+
+ it('throws when a threshold value is not between 0 and 1', function() {
+ expect(function() {
+ io = new IntersectionObserver(noop, {threshold: [0, -1]});
+ }).to.throwException(/threshold/i);
+ });
+
+ it('throws when a threshold value is not a number', function() {
+ expect(function() {
+ io = new IntersectionObserver(noop, {threshold: "foo"});
+ }).to.throwException(/.*/i);
+ });
+
+ });
+
+
+ describe('observe', function() {
+
+ it('throws when target is not an Element', function() {
+ expect(function() {
+ io = new IntersectionObserver(noop);
+ io.observe(null);
+ }).to.throwException(/.*/i);
+ });
+
+
+ it('triggers if target intersects when observing begins', function(done) {
+ io = new IntersectionObserver(function(records) {
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ }, {root: rootEl});
+ io.observe(targetEl1);
+ });
+
+
+ it('triggers with the correct arguments', function(done) {
+ io = new IntersectionObserver(function(records, observer) {
+ expect(records.length).to.be(1);
+ expect(records[0] instanceof IntersectionObserverEntry).to.be.ok();
+ expect(observer).to.be(io);
+ expect(this).to.be(io);
+ done();
+ }, {root: rootEl});
+ io.observe(targetEl1);
+ });
+
+
+ it('does trigger if target does not intersect when observing begins',
+ function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ targetEl2.style.top = '-40px';
+ io.observe(targetEl2);
+ callDelayed(function() {
+ expect(spy.callCount).to.be(1);
+ done();
+ });
+ });
+
+
+ it('triggers if target or root becomes invisible',
+ function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ runSequence([
+ function(done) {
+ io.observe(targetEl1);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(1);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.display = 'none';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(2);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.display = 'block';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(3);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ });
+ },
+ function(done) {
+ rootEl.style.display = 'none';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(4);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0);
+ done();
+ });
+ },
+ function(done) {
+ rootEl.style.display = 'block';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(5);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ });
+ },
+ ], done);
+ });
+
+
+ it('handles container elements with non-visible overflow',
+ function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ runSequence([
+ function(done) {
+ io.observe(targetEl1);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(1);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.left = '-40px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(2);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0);
+ done();
+ });
+ },
+ function(done) {
+ parentEl.style.overflow = 'visible';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(3);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ });
+ }
+ ], done);
+ });
+
+
+ it('observes one target at a single threshold correctly', function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl, threshold: 0.5});
+
+ runSequence([
+ function(done) {
+ targetEl1.style.left = '-5px';
+ io.observe(targetEl1);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(1);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be.greaterThan(0.5);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.left = '-15px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(2);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be.lessThan(0.5);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.left = '-25px';
+ callDelayed(function() {
+ expect(spy.callCount).to.be(2);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.left = '-10px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(3);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0.5);
+ done();
+ });
+ }
+ ], done);
+
+ });
+
+
+ it('observes multiple targets at multiple thresholds correctly',
+ function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {
+ root: rootEl,
+ threshold: [1, 0.5, 0]
+ });
+
+ runSequence([
+ function(done) {
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '-15px';
+ targetEl2.style.top = '-5px';
+ targetEl2.style.left = '0px';
+ targetEl3.style.top = '0px';
+ targetEl3.style.left = '205px';
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ io.observe(targetEl3);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(1);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(3);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(0.25);
+ expect(records[1].target).to.be(targetEl2);
+ expect(records[1].intersectionRatio).to.be(0.75);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '-5px';
+ targetEl2.style.top = '-15px';
+ targetEl2.style.left = '0px';
+ targetEl3.style.top = '0px';
+ targetEl3.style.left = '195px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(2);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(3);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(0.75);
+ expect(records[1].target).to.be(targetEl2);
+ expect(records[1].intersectionRatio).to.be(0.25);
+ expect(records[2].target).to.be(targetEl3);
+ expect(records[2].intersectionRatio).to.be(0.25);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '5px';
+ targetEl2.style.top = '-25px';
+ targetEl2.style.left = '0px';
+ targetEl3.style.top = '0px';
+ targetEl3.style.left = '185px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(3);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(3);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(1);
+ expect(records[1].target).to.be(targetEl2);
+ expect(records[1].intersectionRatio).to.be(0);
+ expect(records[2].target).to.be(targetEl3);
+ expect(records[2].intersectionRatio).to.be(0.75);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '15px';
+ targetEl2.style.top = '-35px';
+ targetEl2.style.left = '0px';
+ targetEl3.style.top = '0px';
+ targetEl3.style.left = '175px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(4);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].target).to.be(targetEl3);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ });
+ }
+ ], done);
+ });
+
+
+ it('handles rootMargin properly', function(done) {
+
+ parentEl.style.overflow = 'visible';
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '-20px';
+ targetEl2.style.top = '-20px';
+ targetEl2.style.left = '0px';
+ targetEl3.style.top = '0px';
+ targetEl3.style.left = '200px';
+ targetEl4.style.top = '180px';
+ targetEl4.style.left = '180px';
+
+ runSequence([
+ function(done) {
+ io = new IntersectionObserver(function(records) {
+ records = sortRecords(records);
+ expect(records.length).to.be(4);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(1);
+ expect(records[1].target).to.be(targetEl2);
+ expect(records[1].intersectionRatio).to.be(.5);
+ expect(records[2].target).to.be(targetEl3);
+ expect(records[2].intersectionRatio).to.be(.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(1);
+ io.disconnect();
+ done();
+ }, {root: rootEl, rootMargin: '10px'});
+
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ io.observe(targetEl3);
+ io.observe(targetEl4);
+ },
+ function(done) {
+ io = new IntersectionObserver(function(records) {
+ records = sortRecords(records);
+ expect(records.length).to.be(4);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(0.5);
+ expect(records[2].target).to.be(targetEl3);
+ expect(records[2].intersectionRatio).to.be(0.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.5);
+ io.disconnect();
+ done();
+ }, {root: rootEl, rootMargin: '-10px 10%'});
+
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ io.observe(targetEl3);
+ io.observe(targetEl4);
+ },
+ function(done) {
+ io = new IntersectionObserver(function(records) {
+ records = sortRecords(records);
+ expect(records.length).to.be(4);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(0.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.5);
+ io.disconnect();
+ done();
+ }, {root: rootEl, rootMargin: '-5% -2.5% 0px'});
+
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ io.observe(targetEl3);
+ io.observe(targetEl4);
+ },
+ function(done) {
+ io = new IntersectionObserver(function(records) {
+ records = sortRecords(records);
+ expect(records.length).to.be(4);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(0.5);
+ expect(records[1].target).to.be(targetEl2);
+ expect(records[1].intersectionRatio).to.be(0.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.25);
+ io.disconnect();
+ done();
+ }, {root: rootEl, rootMargin: '5% -2.5% -10px -190px'});
+
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ io.observe(targetEl3);
+ io.observe(targetEl4);
+ }
+ ], done);
+ });
+
+
+ it('handles targets on the boundary of root', function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ runSequence([
+ function(done) {
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '-21px';
+ targetEl2.style.top = '-20px';
+ targetEl2.style.left = '0px';
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(1);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(2);
+ expect(records[1].intersectionRatio).to.be(0);
+ expect(records[1].target).to.be(targetEl2);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '-20px';
+ targetEl2.style.top = '-21px';
+ targetEl2.style.left = '0px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(2);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(2);
+ expect(records[0].intersectionRatio).to.be(0);
+ expect(records[0].isIntersecting).to.be.ok();
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[1].intersectionRatio).to.be(0);
+ expect(records[1].target).to.be(targetEl2);
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.top = '-20px';
+ targetEl1.style.left = '200px';
+ targetEl2.style.top = '200px';
+ targetEl2.style.left = '200px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(3);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0);
+ expect(records[0].target).to.be(targetEl2);
+ done();
+ });
+ },
+ function(done) {
+ targetEl3.style.top = '20px';
+ targetEl3.style.left = '-20px';
+ targetEl4.style.top = '-20px';
+ targetEl4.style.left = '20px';
+ io.observe(targetEl3);
+ io.observe(targetEl4);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(4);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(2);
+ expect(records[0].intersectionRatio).to.be(0);
+ expect(records[0].isIntersecting).to.be.ok();
+ expect(records[0].target).to.be(targetEl3);
+ expect(records[1].intersectionRatio).to.be(0);
+ expect(records[1].target).to.be(targetEl4);
+ done();
+ });
+ }
+ ], done);
+
+ });
+
+
+ it('handles zero-size targets within the root coordinate space',
+ function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ runSequence([
+ function(done) {
+ targetEl1.style.top = '0px';
+ targetEl1.style.left = '0px';
+ targetEl1.style.width = '0px';
+ targetEl1.style.height = '0px';
+ io.observe(targetEl1);
+ spy.waitForNotification(function() {
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ expect(records[0].isIntersecting).to.be.ok();
+ done();
+ });
+ },
+ function(done) {
+ targetEl1.style.top = '-1px';
+ spy.waitForNotification(function() {
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0);
+ expect(records[0].isIntersecting).to.be(false);
+ done();
+ });
+ }
+ ], done);
+ });
+
+
+ it('handles root/target elements not yet in the DOM', function(done) {
+
+ rootEl.remove();
+ targetEl1.remove();
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ runSequence([
+ function(done) {
+ io.observe(targetEl1);
+ callDelayed(done);
+ },
+ function(done) {
+ document.getElementById('fixtures').appendChild(rootEl);
+ callDelayed(function() {
+ expect(spy.callCount).to.be(1);
+ done();
+ });
+ },
+ function(done) {
+ parentEl.insertBefore(targetEl1, targetEl2);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(2);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ expect(records[0].target).to.be(targetEl1);
+ done();
+ });
+ },
+ function(done) {
+ grandParentEl.remove();
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(3);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0);
+ expect(records[0].target).to.be(targetEl1);
+ done();
+ });
+ },
+ function(done) {
+ rootEl.appendChild(targetEl1);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(4);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ expect(records[0].target).to.be(targetEl1);
+ done();
+ });
+ },
+ function(done) {
+ rootEl.remove();
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(5);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(0);
+ expect(records[0].target).to.be(targetEl1);
+ done();
+ });
+ }
+ ], done);
+ });
+
+
+ it('handles sub-root element scrolling', function(done) {
+ io = new IntersectionObserver(function(records) {
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ }, {root: rootEl});
+
+ io.observe(targetEl3);
+ callDelayed(function() {
+ parentEl.scrollLeft = 40;
+ });
+ });
+
+
+ it('supports CSS transitions and transforms', function(done) {
+
+ targetEl1.style.top = '220px';
+ targetEl1.style.left = '220px';
+
+ var callCount = 0;
+
+ io = new IntersectionObserver(function(records) {
+ callCount++;
+ if (callCount <= 1) {
+ return;
+ }
+ expect(records.length).to.be(1);
+ expect(records[0].intersectionRatio).to.be(1);
+ done();
+ }, {root: rootEl, threshold: [1]});
+
+ io.observe(targetEl1);
+ callDelayed(function() {
+ targetEl1.style.transform = 'translateX(-40px) translateY(-40px)';
+ });
+ });
+
+
+ it('uses the viewport when no root is specified', function(done) {
+ window.onmessage = function (e) {
+ expect(e.data).to.be.ok();
+ win.close();
+ done();
+ };
+
+ var win = window.open("intersectionobserver_window.html");
+ });
+
+ it('triggers only once if observed multiple times (and does not crash when collected)', function(done) {
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+ io.observe(targetEl1);
+ io.observe(targetEl1);
+ io.observe(targetEl1);
+
+ spy.waitForNotification(function() {
+ callDelayed(function () {
+ expect(spy.callCount).to.be(1);
+ done();
+ });
+ });
+ });
+
+ });
+
+ describe('observe subframe', function () {
+
+ it('boundingClientRect matches target.getBoundingClientRect() for an element inside an iframe',
+ function(done) {
+
+ io = new IntersectionObserver(function(records) {
+ expect(records.length).to.be(1);
+ expect(records[0].boundingClientRect.top, targetEl5.getBoundingClientRect().top);
+ expect(records[0].boundingClientRect.left, targetEl5.getBoundingClientRect().left);
+ expect(records[0].boundingClientRect.width, targetEl5.getBoundingClientRect().width);
+ expect(records[0].boundingClientRect.height, targetEl5.getBoundingClientRect().height);
+ done();
+ }, {threshold: [1]});
+
+ targetEl4.onload = function () {
+ targetEl5 = targetEl4.contentDocument.getElementById('target5');
+ io.observe(targetEl5);
+ }
+
+ targetEl4.src = "intersectionobserver_iframe.html";
+ });
+
+ it('rootBounds is set to null for cross-origin observations', function(done) {
+
+ window.onmessage = function (e) {
+ expect(e.data).to.be(true);
+ done();
+ };
+
+ targetEl4.src = "http://example.org/tests/dom/base/test/intersectionobserver_cross_domain_iframe.html";
+
+ });
+
+ });
+
+ describe('takeRecords', function() {
+
+ it('supports getting records before the callback is invoked', function(done) {
+
+ var lastestRecords = [];
+ io = new IntersectionObserver(function(records) {
+ lastestRecords = lastestRecords.concat(records);
+ }, {root: rootEl});
+ io.observe(targetEl1);
+
+ window.requestAnimationFrame && requestAnimationFrame(function wait() {
+ lastestRecords = lastestRecords.concat(io.takeRecords());
+ if (!lastestRecords.length) {
+ requestAnimationFrame(wait);
+ return;
+ }
+ callDelayed(function() {
+ expect(lastestRecords.length).to.be(1);
+ expect(lastestRecords[0].intersectionRatio).to.be(1);
+ done();
+ });
+ });
+
+ });
+
+ });
+
+ describe('unobserve', function() {
+
+ it('removes targets from the internal store', function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ runSequence([
+ function(done) {
+ targetEl1.style.top = targetEl2.style.top = '0px';
+ targetEl1.style.left = targetEl2.style.left = '0px';
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(1);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(2);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(1);
+ expect(records[1].target).to.be(targetEl2);
+ expect(records[1].intersectionRatio).to.be(1);
+ done();
+ });
+ },
+ function(done) {
+ io.unobserve(targetEl1);
+ targetEl1.style.top = targetEl2.style.top = '0px';
+ targetEl1.style.left = targetEl2.style.left = '-40px';
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(2);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(1);
+ expect(records[0].target).to.be(targetEl2);
+ expect(records[0].intersectionRatio).to.be(0);
+ done();
+ });
+ },
+ function(done) {
+ io.unobserve(targetEl2);
+ targetEl1.style.top = targetEl2.style.top = '0px';
+ targetEl1.style.left = targetEl2.style.left = '0px';
+ callDelayed(function() {
+ expect(spy.callCount).to.be(2);
+ done();
+ });
+ }
+ ], done);
+
+ });
+
+ });
+
+ describe('disconnect', function() {
+
+ it('removes all targets and stops listening for changes', function(done) {
+
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+
+ runSequence([
+ function(done) {
+ targetEl1.style.top = targetEl2.style.top = '0px';
+ targetEl1.style.left = targetEl2.style.left = '0px';
+ io.observe(targetEl1);
+ io.observe(targetEl2);
+ spy.waitForNotification(function() {
+ expect(spy.callCount).to.be(1);
+ var records = sortRecords(spy.lastCall.args[0]);
+ expect(records.length).to.be(2);
+ expect(records[0].target).to.be(targetEl1);
+ expect(records[0].intersectionRatio).to.be(1);
+ expect(records[1].target).to.be(targetEl2);
+ expect(records[1].intersectionRatio).to.be(1);
+ done();
+ });
+ },
+ function(done) {
+ io.disconnect();
+ targetEl1.style.top = targetEl2.style.top = '0px';
+ targetEl1.style.left = targetEl2.style.left = '-40px';
+ callDelayed(function() {
+ expect(spy.callCount).to.be(1);
+ done();
+ });
+ }
+ ], done);
+
+ });
+
+ });
+
+ });
+
+
+ /**
+ * Runs a sequence of function and when finished invokes the done callback.
+ * Each function in the sequence is invoked with its own done function and
+ * it should call that function once it's complete.
+ * @param {Array<Function>} functions An array of async functions.
+ * @param {Function} done A final callback to be invoked once all function
+ * have run.
+ */
+ function runSequence(functions, done) {
+ var next = functions.shift();
+ if (next) {
+ next(function() {
+ runSequence(functions, done);
+ });
+ } else {
+ done && done();
+ }
+ }
+
+
+ /**
+ * Sorts an array of records alphebetically by ascending ID. Since the current
+ * native implementation doesn't sort change entries by `observe` order, we do
+ * that ourselves for the non-polyfill case. Since all tests call observe
+ * on targets in sequential order, this should always match.
+ * https://crbug.com/613679
+ * @param {Array<IntersectionObserverEntry>} entries The entries to sort.
+ * @return {Array<IntersectionObserverEntry>} The sorted array.
+ */
+ function sortRecords(entries) {
+ entries = entries.sort(function(a, b) {
+ return a.target.id < b.target.id ? -1 : 1;
+ });
+ return entries;
+ }
+
+
+ /**
+ * Adds the common styles used by all tests to the page.
+ */
+ function addStyles() {
+ var styles = document.createElement('style');
+ styles.id = 'styles';
+ document.documentElement.appendChild(styles);
+
+ var cssText =
+ '#root {' +
+ ' position: relative;' +
+ ' width: 400px;' +
+ ' height: 200px;' +
+ ' background: #eee' +
+ '}' +
+ '#grand-parent {' +
+ ' position: relative;' +
+ ' width: 200px;' +
+ ' height: 200px;' +
+ '}' +
+ '#parent {' +
+ ' position: absolute;' +
+ ' top: 0px;' +
+ ' left: 200px;' +
+ ' overflow: hidden;' +
+ ' width: 200px;' +
+ ' height: 200px;' +
+ ' background: #ddd;' +
+ '}' +
+ '#target1, #target2, #target3, #target4 {' +
+ ' position: absolute;' +
+ ' top: 0px;' +
+ ' left: 0px;' +
+ ' width: 20px;' +
+ ' height: 20px;' +
+ ' transform: translateX(0px) translateY(0px);' +
+ ' transition: transform .5s;' +
+ ' background: #f00;' +
+ ' border: none;' +
+ '}';
+
+ styles.innerHTML = cssText;
+ }
+
+
+ /**
+ * Adds the DOM fixtures used by all tests to the page and assigns them to
+ * global variables so they can be referenced within the tests.
+ */
+ function addFixtures() {
+ var fixtures = document.createElement('div');
+ fixtures.id = 'fixtures';
+
+ fixtures.innerHTML =
+ '<div id="root">' +
+ ' <div id="grand-parent">' +
+ ' <div id="parent">' +
+ ' <div id="target1"></div>' +
+ ' <div id="target2"></div>' +
+ ' <div id="target3"></div>' +
+ ' <iframe id="target4"></iframe>' +
+ ' </div>' +
+ ' </div>' +
+ '</div>';
+
+ document.body.appendChild(fixtures);
+
+ rootEl = document.getElementById('root');
+ grandParentEl = document.getElementById('grand-parent');
+ parentEl = document.getElementById('parent');
+ targetEl1 = document.getElementById('target1');
+ targetEl2 = document.getElementById('target2');
+ targetEl3 = document.getElementById('target3');
+ targetEl4 = document.getElementById('target4');
+ }
+
+
+ /**
+ * Removes the common styles from the page.
+ */
+ function removeStyles() {
+ var styles = document.getElementById('styles');
+ styles.remove();
+ }
+
+
+ /**
+ * Removes the DOM fixtures from the page and resets the global references.
+ */
+ function removeFixtures() {
+ var fixtures = document.getElementById('fixtures');
+ fixtures.remove();
+
+ rootEl = null;
+ grandParentEl = null;
+ parentEl = null;
+ targetEl1 = null;
+ targetEl2 = null;
+ targetEl3 = null;
+ targetEl4 = null;
+ }
+
+ function onLoad() {
+ next();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+<div id="log">
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_link_prefetch.html b/dom/base/test/test_link_prefetch.html
new file mode 100644
index 0000000000..5a5e7a0bbc
--- /dev/null
+++ b/dom/base/test/test_link_prefetch.html
@@ -0,0 +1,220 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test link policy attribute for Bug 1264165</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that link referrer attributes are honoured correctly
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1264165
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL", "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-link-policy-test"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'prefetch-unsafe-url-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'prefetch',
+ DESC: "prefetch-unsafe-url with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'prefetch-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ REL: 'prefetch',
+ DESC: "prefetch-origin with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'prefetch-no-referrer-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'prefetch',
+ DESC: "prefetch-no-referrer with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'prefetch-same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'prefetch',
+ DESC: "prefetch-same-origin with origin in meta",
+ RESULT: 'full'},
+ {NAME: 'prefetch-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'prefetch',
+ DESC: "prefetch-no-referrer in meta",
+ RESULT: 'none'},
+
+ // Downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'prefetch-origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'prefetch-origin in meta downgrade in attr',
+ REL: 'prefetch',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'prefetch-origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'prefetch-origin in meta strict-origin in attr',
+ REL: 'prefetch',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'prefetch-origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'prefetch-origin in meta strict-origin-when-cross-origin in attr',
+ REL: 'prefetch',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+
+ // No downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'prefetch-origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'prefetch-origin in meta downgrade in attr',
+ REL: 'prefetch',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'prefetch-origin-with-no-meta',
+ META_POLICY: '',
+ REL: 'prefetch',
+ DESC: "prefetch-origin with no meta",
+ RESULT: 'origin'},
+
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'prefetch-origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'prefetch-origin in meta strict-origin in attr',
+ REL: 'prefetch',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'prefetch-origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'prefetch-origin in meta strict-origin-when-cross-origin in attr',
+ REL: 'prefetch',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+
+ // Cross origin
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'prefetch-origin-when-cross-origin-with-no-meta',
+ META_POLICY: '',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'prefetch',
+ DESC: "prefetch-origin-when-cross-origin with no meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'prefetch-origin-when-cross-origin-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'prefetch',
+ DESC: "prefetch-origin-when-cross-origin with no-referrer in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'prefetch-origin-when-cross-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'prefetch',
+ DESC: "prefetch-origin-when-cross-origin with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'prefetch-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'prefetch',
+ DESC: "prefetch-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'prefetch-strict-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ REL: 'prefetch',
+ DESC: "prefetch-strict-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'prefetch-same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ REL: 'prefetch',
+ DESC: "prefetch-same-origin with origin in meta",
+ RESULT: 'none'},
+
+ // Invalid
+ {ATTRIBUTE_POLICY: 'default',
+ NAME: 'prefetch-default-with-no-meta',
+ META_POLICY: '',
+ REL: 'prefetch',
+ DESC: "prefetch-default with no meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'something',
+ NAME: 'prefetch-something-with-no-meta',
+ META_POLICY: '',
+ REL: 'prefetch',
+ DESC: "prefetch-something with no meta",
+ RESULT: 'full'},
+ ]},
+
+ {ACTION: ["generate-link-policy-test-set-attribute"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NEW_ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'prefetch-no-referrer-unsafe-url-set-attribute-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'prefetch',
+ DESC: "prefetch-no-referrer-set-attribute (orginally unsafe-url) with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'prefetch-unsafe-url-origin-set-attribute-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'prefetch',
+ DESC: "prefetch-unsafe-url-set-attribute(orginally origin) with no-referrer in meta",
+ RESULT: 'full'},
+ ]},
+
+ {ACTION: ["generate-link-policy-test-property"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'prefetch-unsafe-url-no-referrer-property-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'prefetch',
+ DESC: "prefetch-unsafe-url-property (orginally no-referrer) with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'prefetch-unsafe-url-origin-property-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'prefetch',
+ DESC: "prefetch-unsafe-url-property (orginally origin) with no-referrer in meta",
+ RESULT: 'full'},
+ ]},
+ ];
+
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/test_link_preload.html b/dom/base/test/test_link_preload.html
new file mode 100644
index 0000000000..6e57f4a46d
--- /dev/null
+++ b/dom/base/test/test_link_preload.html
@@ -0,0 +1,220 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test preload referrer policy for Bug 1399780</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that link referrer attributes are honoured correctly for rel=preload
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1399780
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL", "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-link-policy-test"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'preload-unsafe-url-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'preload',
+ DESC: "preload-unsafe-url with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'preload-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ REL: 'preload',
+ DESC: "preload-origin with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'preload-no-referrer-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'preload',
+ DESC: "preload-no-referrer with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'preload-same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'preload',
+ DESC: "preload-same-origin with origin in meta",
+ RESULT: 'full'},
+ {NAME: 'preload-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'preload',
+ DESC: "preload-no-referrer in meta",
+ RESULT: 'none'},
+
+ // Downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'preload-origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'preload-origin in meta downgrade in attr',
+ REL: 'preload',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'preload-origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'preload-origin in meta strict-origin in attr',
+ REL: 'preload',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'preload-origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'preload-origin in meta strict-origin-when-cross-origin in attr',
+ REL: 'preload',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+
+ // No downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'preload-origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'preload-origin in meta downgrade in attr',
+ REL: 'preload',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'preload-origin-with-no-meta',
+ META_POLICY: '',
+ REL: 'preload',
+ DESC: "preload-origin with no meta",
+ RESULT: 'origin'},
+
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'preload-origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'preload-origin in meta strict-origin in attr',
+ REL: 'preload',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'preload-origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'preload-origin in meta strict-origin-when-cross-origin in attr',
+ REL: 'preload',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+
+ // Cross origin
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'preload-origin-when-cross-origin-with-no-meta',
+ META_POLICY: '',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'preload',
+ DESC: "preload-origin-when-cross-origin with no meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'preload-origin-when-cross-origin-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'preload',
+ DESC: "preload-origin-when-cross-origin with no-referrer in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'preload-origin-when-cross-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'preload',
+ DESC: "preload-origin-when-cross-origin with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'preload-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'preload',
+ DESC: "preload-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'preload-strict-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ REL: 'preload',
+ DESC: "preload-strict-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'preload-same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ REL: 'preload',
+ DESC: "preload-same-origin with origin in meta",
+ RESULT: 'none'},
+
+ // Invalid
+ {ATTRIBUTE_POLICY: 'default',
+ NAME: 'preload-default-with-no-meta',
+ META_POLICY: '',
+ REL: 'preload',
+ DESC: "preload-default with no meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'something',
+ NAME: 'preload-something-with-no-meta',
+ META_POLICY: '',
+ REL: 'preload',
+ DESC: "preload-something with no meta",
+ RESULT: 'full'},
+ ]},
+
+ {ACTION: ["generate-link-policy-test-set-attribute"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NEW_ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'preload-no-referrer-unsafe-url-set-attribute-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'preload',
+ DESC: "preload-no-referrer-set-attribute (orginally unsafe-url) with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'preload-unsafe-url-origin-set-attribute-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'preload',
+ DESC: "preload-unsafe-url-set-attribute(orginally origin) with no-referrer in meta",
+ RESULT: 'full'},
+ ]},
+
+ {ACTION: ["generate-link-policy-test-property"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'preload-unsafe-url-no-referrer-property-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'preload',
+ DESC: "preload-unsafe-url-property (orginally no-referrer) with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'preload-unsafe-url-origin-property-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'preload',
+ DESC: "preload-unsafe-url-property (orginally origin) with no-referrer in meta",
+ RESULT: 'full'},
+ ]},
+ ];
+
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/test_link_stylesheet.html b/dom/base/test/test_link_stylesheet.html
new file mode 100644
index 0000000000..d699d22ee2
--- /dev/null
+++ b/dom/base/test/test_link_stylesheet.html
@@ -0,0 +1,221 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test link policy attribute for Bug 1264165</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <!--
+ Testing that link referrer attributes are honoured correctly
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1264165
+ -->
+
+ <script type="application/javascript">
+
+ const SJS = "://example.com/tests/dom/base/test/referrer_testserver.sjs?";
+ const PARAMS = ["ATTRIBUTE_POLICY", "NEW_ATTRIBUTE_POLICY", "META_POLICY", "REL", "SCHEME_FROM", "SCHEME_TO"];
+
+ const testCases = [
+ {ACTION: ["generate-link-policy-test"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'stylesheet-unsafe-url-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'stylesheet',
+ DESC: "stylesheet-unsafe-url with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'stylesheet-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ REL: 'stylesheet',
+ DESC: "stylesheet-origin with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'stylesheet-no-referrer-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'stylesheet',
+ DESC: "stylesheet-no-referrer with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'stylesheet-same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'stylesheet',
+ DESC: "stylesheet-same-origin with origin in meta",
+ RESULT: 'full'},
+ {NAME: 'stylesheet-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'stylesheet',
+ DESC: "stylesheet-no-referrer in meta",
+ RESULT: 'none'},
+
+ // Downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'stylesheet-origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'stylesheet-origin in meta downgrade in attr',
+ REL: 'stylesheet',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'stylesheet-origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'stylesheet-origin in meta strict-origin in attr',
+ REL: 'stylesheet',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'stylesheet-origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'stylesheet-origin in meta strict-origin-when-cross-origin in attr',
+ REL: 'stylesheet',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ RESULT: 'none'},
+
+ // No downgrade.
+ {ATTRIBUTE_POLICY: 'no-referrer-when-downgrade',
+ NAME: 'stylesheet-origin-in-meta-downgrade-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'stylesheet-origin in meta downgrade in attr',
+ REL: 'stylesheet',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+
+ {ATTRIBUTE_POLICY: 'origin',
+ NAME: 'stylesheet-origin-with-no-meta',
+ META_POLICY: '',
+ REL: 'stylesheet',
+ DESC: "stylesheet-origin with no meta",
+ RESULT: 'origin'},
+
+ {ATTRIBUTE_POLICY: 'strict-origin',
+ NAME: 'stylesheet-origin-in-meta-strict-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'stylesheet-origin in meta strict-origin in attr',
+ REL: 'stylesheet',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'stylesheet-origin-in-meta-strict-origin-when-cross-origin-in-attr',
+ META_POLICY: 'origin',
+ DESC: 'stylesheet-origin in meta strict-origin-when-cross-origin in attr',
+ REL: 'stylesheet',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'https',
+ RESULT: 'full'},
+
+ // Cross origin
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'stylesheet-origin-when-cross-origin-with-no-meta',
+ META_POLICY: '',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'stylesheet',
+ DESC: "stylesheet-origin-when-cross-origin with no meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'stylesheet-origin-when-cross-origin-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'stylesheet',
+ DESC: "stylesheet-origin-when-cross-origin with no-referrer in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'stylesheet-origin-when-cross-origin-with-unsafe-url-in-meta',
+ META_POLICY: 'unsafe-url',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'stylesheet',
+ DESC: "stylesheet-origin-when-cross-origin with unsafe-url in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'origin-when-cross-origin',
+ NAME: 'stylesheet-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'https',
+ SCHEME_TO: 'http',
+ REL: 'stylesheet',
+ DESC: "stylesheet-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'strict-origin-when-cross-origin',
+ NAME: 'stylesheet-strict-origin-when-cross-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ REL: 'stylesheet',
+ DESC: "stylesheet-strict-origin-when-cross-origin with origin in meta",
+ RESULT: 'origin'},
+ {ATTRIBUTE_POLICY: 'same-origin',
+ NAME: 'stylesheet-same-origin-with-origin-in-meta',
+ META_POLICY: 'origin',
+ SCHEME_FROM: 'http',
+ SCHEME_TO: 'https',
+ REL: 'stylesheet',
+ DESC: "stylesheet-same-origin with origin in meta",
+ RESULT: 'none'},
+
+ // Invalid
+ {ATTRIBUTE_POLICY: 'default',
+ NAME: 'stylesheet-default-with-no-meta',
+ META_POLICY: '',
+ REL: 'stylesheet',
+ DESC: "stylesheet-default with no meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'something',
+ NAME: 'stylesheet-something-with-no-meta',
+ META_POLICY: '',
+ REL: 'stylesheet',
+ DESC: "stylesheet-something with no meta",
+ RESULT: 'full'},
+ ]},
+
+ {ACTION: ["generate-link-policy-test-set-attribute"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'unsafe-url',
+ NEW_ATTRIBUTE_POLICY: 'no-referrer',
+ NAME: 'stylesheet-no-referrer-unsafe-url-set-attribute-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'stylesheet',
+ DESC: "stylesheet-no-referrer-set-attribute (orginally unsafe-url) with origin in meta",
+ RESULT: 'none'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'stylesheet-unsafe-url-origin-set-attribute-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'stylesheet',
+ DESC: "stylesheet-unsafe-url-set-attribute (orginally origin) with no-referrer in meta",
+ RESULT: 'full'},
+ ]},
+
+ {ACTION: ["generate-link-policy-test-property"],
+ TESTS: [
+ {ATTRIBUTE_POLICY: 'no-referrer',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'stylesheet-unsafe-url-no-referrer-property-with-origin-in-meta',
+ META_POLICY: 'origin',
+ REL: 'stylesheet',
+ DESC: "stylesheet-unsafe-url-property (orginally no-referrer) with origin in meta",
+ RESULT: 'full'},
+ {ATTRIBUTE_POLICY: 'origin',
+ NEW_ATTRIBUTE_POLICY: 'unsafe-url',
+ NAME: 'stylesheet-unsafe-url-origin-property-with-no-referrer-in-meta',
+ META_POLICY: 'no-referrer',
+ REL: 'stylesheet',
+ DESC: "stylesheet-unsafe-url-property (orginally origin) with no-referrer in meta",
+ RESULT: 'full'},
+ ]},
+ ];
+ </script>
+ <script type="application/javascript" src="/tests/dom/base/test/referrer_helper.js"></script>
+</head>
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_location_href_unknown_protocol.html b/dom/base/test/test_location_href_unknown_protocol.html
new file mode 100644
index 0000000000..15448ff82d
--- /dev/null
+++ b/dom/base/test/test_location_href_unknown_protocol.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Test for window.location setter to an unknown protocol (bug 1528305).</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+SimpleTest.waitForExplicitFinish();
+let beforeunload = false;
+let unload = false;
+
+window.onChildBeforeUnload = function() {
+ beforeunload = true;
+};
+
+window.onChildUnload = function() {
+ unload = true;
+};
+
+let win;
+window.onChildLoadTimedOut = function() {
+ ok(!unload, "shouldn't have unloaded child window");
+ ok(beforeunload, "should've fired a beforeunload event");
+ win.close();
+ SimpleTest.finish();
+};
+
+win = window.open("file_location_href_unknown_protocol.html");
+</script>
diff --git a/dom/base/test/test_lock_orientation_after_fullscreen.html b/dom/base/test/test_lock_orientation_after_fullscreen.html
new file mode 100644
index 0000000000..bb448f2b8d
--- /dev/null
+++ b/dom/base/test/test_lock_orientation_after_fullscreen.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1757431
+-->
+<head>
+<title>Test for Bug 1757431</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=1757431">Mozilla Bug 1757431</a>
+<div id="fullscreen">fullscreen</div>
+<script>
+add_task(async () => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.screenorientation.allow-lock", true]]
+ });
+
+ const element = document.getElementById("fullscreen");
+ await SpecialPowers.wrap(element).requestFullscreen();
+ let newOrientationLock = SpecialPowers.getDOMWindowUtils(window).orientationLock;
+
+ ok(document.fullscreen, "Document should be in fullscreen");
+ is(newOrientationLock, 0, "Orientation lock in browsing context should be none by enterFullscreen");
+
+ const originalOrientationType = window.screen.orientation.type;
+ const newOrientationType = originalOrientationType.startsWith("landscape") ? "portrait-primary" : "landscape-primary";
+
+ await window.screen.orientation.lock(newOrientationType);
+ newOrientationLock = SpecialPowers.getDOMWindowUtils(window).orientationLock;
+ if (newOrientationType == "portrait-primary") {
+ is(newOrientationLock, 1, "Orientation lock in browsing context should be portrait-primary");
+ } else {
+ is(newOrientationLock, 4, "Orientation lock in browsing context should be landscape-primary");
+ }
+
+ await window.screen.orientation.lock(originalOrientationType);
+ newOrientationLock = SpecialPowers.getDOMWindowUtils(window).orientationLock;
+ if (originalOrientationType == "portrait-primary") {
+ is(newOrientationLock, 1, "Orientation lock in browsing context should be portrait-primary");
+ } else {
+ is(newOrientationLock, 4, "Orientation lock in browsing context should be landscape-primary");
+ }
+
+ await document.exitFullscreen();
+
+ // Wait fullscreen change in ScreenOrientation
+ await new Promise(r =>
+ window.requestAnimationFrame(() => window.requestAnimationFrame(r))
+ );
+
+ newOrientationLock = SpecialPowers.getDOMWindowUtils(window).orientationLock;
+ is(newOrientationLock, 0, "Orientation lock in browsing context should be none by exitFullscreen");
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_lock_orientation_with_pending_fullscreen.html b/dom/base/test/test_lock_orientation_with_pending_fullscreen.html
new file mode 100644
index 0000000000..7df60a7e72
--- /dev/null
+++ b/dom/base/test/test_lock_orientation_with_pending_fullscreen.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1744288
+-->
+<head>
+<meta charset="utf-8">
+<title>Test for Bug 1744288</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=174488">Mozilla Bug 1744288</a>
+<script>
+const kIsWin = navigator.platform.indexOf("Win") == 0;
+
+add_task(async function test_pending_fullscreen_request() {
+ if (kIsWin) {
+ // CI won't run on Windows tablet mode.
+ ok(true, "Skip on Windows");
+ return;
+ }
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.screenorientation.allow-lock", true]]
+ });
+
+ SpecialPowers.wrap(document.documentElement).requestFullscreen();
+ let gotException = false;
+ try {
+ await window.screen.orientation.lock("any");
+ } catch (e) {
+ gotException = true;
+ }
+ ok(!gotException, "No exception even if fullscreen request is pending.");
+
+ window.screen.orientation.unlock();
+ try {
+ await document.exitFullscreen();
+ } catch (e) {
+ }
+});
+
+// Gecko doesn't allow orientation lock without fullscreen by default
+add_task(async function test_no_fullscreen_request() {
+ if (kIsWin) {
+ // CI won't run on Windows tablet mode.
+ ok(true, "Skip on Windows");
+ return;
+ }
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.screenorientation.allow-lock", true]]
+ });
+
+ let gotException = false;
+ try {
+ await window.screen.orientation.lock("any");
+ } catch (e) {
+ gotException = true;
+ }
+ ok(gotException, "Should throw an exception when fullscreen request is nothing.");
+});
+
+// Gecko doesn't allow orientation lock after fullscreen request is canceled
+add_task(async function test_cancel_pending_fullscreen_request() {
+ if (kIsWin) {
+ // CI won't run on Windows tablet mode.
+ ok(true, "Skip on Windows");
+ return;
+ }
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.screenorientation.allow-lock", true]]
+ });
+
+ const element = document.createElement("div");
+ document.body.appendChild(element);
+ SpecialPowers.wrap(element).requestFullscreen().then(() => {
+ ok(false, "Fullscreen request should be canceled.");
+ }, () => {
+ ok(true, "Fullscreen request is canceled.");
+ });
+ let gotException = false;
+ try {
+ const promise = window.screen.orientation.lock("any");
+ // Removing element causes that fullscreen request is canceled.
+ document.body.removeChild(element);
+ await promise;
+ } catch (e) {
+ gotException = true;
+ }
+ ok(gotException, "Should throw an exception when pending fullscreen request is canceled.");
+
+ try {
+ window.screen.orientation.unlock();
+ await document.exitFullscreen();
+ } catch (e) {
+ }
+});
+
+add_task(async function test_dont_leak_memory_with_pending_fullscreen_request() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.screenorientation.allow-lock", true]]
+ });
+
+ const iframe = document.createElement("iframe");
+ iframe.setAttribute("allowFullScreen", "");
+ iframe.src = "file_lock_orientation_with_pending_fullscreen.html";
+
+ const promise = new Promise(resolve => {
+ window.addEventListener("message", function handler(e) {
+ if (e.data === "pending") {
+ document.body.removeChild(iframe);
+ window.removeEventListener("message", handler);
+ resolve();
+ }
+ });
+ });
+
+ document.body.appendChild(iframe);
+ await promise;
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_messagePort.html b/dom/base/test/test_messagePort.html
new file mode 100644
index 0000000000..c4fc9d11ce
--- /dev/null
+++ b/dom/base/test/test_messagePort.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=912456
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 912456 - port cloning</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=912456">Mozilla Bug 912456</a>
+<script type="application/javascript">
+
+ function testTransfer() {
+ var a = new MessageChannel();
+ ok(a, "MessageChannel created");
+
+ window.addEventListener('message', receiveMessage);
+ function receiveMessage(evt) {
+ ok(evt.data.port, "Port has been received!");
+
+ var a1 = new MessageChannel();
+ ok(a1, "MessageChannel created");
+
+ try {
+ evt.data.port.postMessage({port: a1.port2});
+ ok(false, "PostMessage should throw! - no transfered port");
+ } catch(e) {
+ ok(true, "PostMessage should throw! - no transfered port");
+ }
+
+ try {
+ evt.data.port.postMessage({port: a1.port2}, [a1.port2, a1.port2]);
+ ok(false, "PostMessage should throw - no duplicate!");
+ } catch(e) {
+ ok(true, "PostMessage should throw - no duplicate!");
+ }
+
+ evt.data.port.postMessage({port: a1.port2}, [a1.port2]);
+ }
+
+ a.port1.onmessage = function(evt) {
+ ok(evt.data.port, "Port has been received!");
+ window.removeEventListener('message', receiveMessage);
+ runTest();
+ }
+
+ try {
+ postMessage({ port: a.port2}, 42, '*');
+ ok(false, "PostMessage should throw! - no transfered port");
+ } catch(e) {
+ ok(true, "PostMessage should throw! - no transfered port");
+ }
+
+ try {
+ postMessage({ port: a.port2}, 42, '*', [a.port2, a.port2]);
+ ok(false, "PostMessage should throw - no duplicate!");
+ } catch(e) {
+ ok(true, "PostMessage should throw - no duplicate!");
+ }
+
+ postMessage({port: a.port2}, '*', [a.port2]);
+ }
+
+ function testPorts() {
+ var a = new MessageChannel();
+ ok(a, "MessageChannel created");
+
+ window.addEventListener('message', receiveMessage);
+ function receiveMessage(evt) {
+ ok(evt.data, "Data is 42");
+ ok(evt.ports, "Port is received");
+ is(evt.ports.length, 1, "Ports.length is 1");
+
+ var a1 = new MessageChannel();
+ ok(a1, "MessageChannel created");
+
+ evt.ports[0].postMessage(42, [a1.port2]);
+ }
+
+ a.port1.onmessage = function(evt) {
+ ok(evt.data, "Data is 42");
+ ok(evt.ports, "Port is received");
+ is(evt.ports.length, 1, "Ports.length is 1");
+ window.removeEventListener('message', receiveMessage);
+ runTest();
+ }
+
+ postMessage(42, '*', [a.port2]);
+ }
+
+ var tests = [
+ testTransfer,
+ testPorts
+ ];
+
+ function runTest() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ runTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_messagemanager_send_principal.html b/dom/base/test/test_messagemanager_send_principal.html
new file mode 100644
index 0000000000..31cc700317
--- /dev/null
+++ b/dom/base/test/test_messagemanager_send_principal.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Principal in MessageManager</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+</head>
+<body>
+
+ <script type="application/javascript">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+
+ const childFrameURL =
+ "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
+
+ function childFrameScript() {
+ "use strict";
+
+
+ addMessageListener("test:content", function(message) {
+ sendAsyncMessage("test:result", "is nsIPrincipal: " +
+ (message.data instanceof Ci.nsIPrincipal ? "OK" : "KO"));
+
+ sendAsyncMessage("test:result", "principal.origin: " +
+ ("origin" in message.data ? "OK" : "KO"));
+ });
+
+ addMessageListener("test:system", function(message) {
+ sendAsyncMessage("test:result", "isSystemPrincipal: " +
+ (message.data.isSystemPrincipal ? "OK" : "KO"));
+ });
+
+ addMessageListener("test:ep", function(message) {
+ sendAsyncMessage("test:result", "expanded principal: " +
+ (message.data.isExpandedPrincipal ? "OK" : "KO"));
+ sendAsyncMessage("test:result", "correct origin: " +
+ (message.data.origin == "[Expanded Principal [http://bar.example.com, http://foo.example.com]]" ? "OK" : "KO"));
+ });
+
+ addMessageListener("test:null", function(message) {
+ sendAsyncMessage("test:result", "is nsIPrincipal: " +
+ (message.data instanceof Ci.nsIPrincipal ? "OK" : "KO"));
+
+ sendAsyncMessage("test:result", "isNullPrincipal: " +
+ (message.data.isNullPrincipal ? "OK" : "KO"));
+ sendAsyncMessage("test:result", "DONE");
+ });
+ }
+
+ function runTests() {
+ ok("Browser prefs set.");
+
+ let iframe = document.createXULElement("browser");
+ iframe.setAttribute("type", "content");
+ iframe.setAttribute("forcemessagemanager", "true");
+ iframe.id = "iframe";
+ iframe.src = childFrameURL;
+
+ let sb = new Cu.Sandbox(['http://foo.example.com', 'http://bar.example.com']);
+ let ep = Cu.getObjectPrincipal(sb);
+
+ iframe.addEventListener("load", function() {
+ ok(true, "Got iframe load event.");
+
+ let mm = iframe.messageManager;
+ mm.addMessageListener("test:result", function(message) {
+ // We need to wrap to access message.json, and unwrap to do the
+ // identity check.
+ var msg = SpecialPowers.unwrap(SpecialPowers.wrap(message).data);
+ if (/OK$/.exec(msg)) {
+ ok(true, msg);
+ } else if(/KO$/.exec(msg)) {
+ ok(true, false);
+ } else if (/DONE/.exec(msg)) {
+ SimpleTest.finish();
+ }
+ });
+ mm.loadFrameScript("data:,(" + childFrameScript.toString() + ")();",
+ false);
+
+ mm.sendAsyncMessage("test:content", window.document.nodePrincipal);
+
+ let system = Services.scriptSecurityManager.getSystemPrincipal();
+ mm.sendAsyncMessage("test:system", system);
+
+ mm.sendAsyncMessage("test:ep", ep);
+
+ let nullP = Services.scriptSecurityManager.createNullPrincipal({});
+ mm.sendAsyncMessage("test:null", nullP);
+ });
+
+ document.body.appendChild(iframe);
+ }
+
+ addEventListener("load", function() {
+ info("Got load event.");
+
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["browser.pagethumbnails.capturing_disabled", true]
+ ]
+ }, runTests);
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_meta_refresh_referrer.html b/dom/base/test/test_meta_refresh_referrer.html
new file mode 100644
index 0000000000..2af0a1f1f8
--- /dev/null
+++ b/dom/base/test/test_meta_refresh_referrer.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name='referrer' content='origin'>
+ <title>Test for referrer of meta refresh request</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * Listen for notifications from the child.
+ */
+window.addEventListener("message", function(event) {
+ if (event.data == "childLoadComplete") {
+ advance();
+ }
+});
+
+var tests = (function*() {
+ var iframe = document.getElementById("testframe");
+
+ // reset counter to make the test pass --repeat test
+ yield reset();
+
+ // load the test frame
+ yield iframe.src =
+ '/tests/dom/base/test/iframe_meta_refresh.sjs?action=test&load=refresh';
+
+ // check the test result
+ yield checkResults(referrerHeaderChecker);
+
+ // complete.
+ SimpleTest.finish();
+})();
+
+function referrerHeaderChecker(results) {
+ var expected = {'count': 2, 'referrers': ['origin', 'none']};
+ is(results.count, expected.count, "Correct number of referrer header");
+ is(results.referrers[0], expected.referrers[0], "Correct load referrer header");
+ is(results.referrers[1], expected.referrers[1], "Correct refresh referrer header");
+
+ advance();
+}
+
+/**
+ * helper to perform an XHR.
+ */
+function doXHR(url, onSuccess, onFail) {
+ var xhr = new XMLHttpRequest();
+ xhr.onload = function () {
+ if (xhr.status == 200) {
+ onSuccess(xhr);
+ } else {
+ onFail(xhr);
+ }
+ };
+ xhr.open('GET', url, true);
+ xhr.send(null);
+}
+
+/**
+ * Grabs the results via XHR and passes to checker.
+ */
+function checkResults(checker) {
+ doXHR('/tests/dom/base/test/iframe_meta_refresh.sjs?action=results',
+ function(xhr) {
+ checker(JSON.parse(xhr.responseText));
+ },
+ function(xhr) {
+ ok(false, "Can't get results from server.");
+ });
+}
+
+/**
+ * Reset the counter.
+ */
+function reset() {
+ doXHR('/tests/dom/base/test/iframe_meta_refresh.sjs?action=reset',
+ advance,
+ function(xhr) {
+ ok(false, "error in reset state");
+ SimpleTest.finish();
+ });
+}
+
+</script>
+</head>
+
+<body onload="tests.next();">
+ <iframe id="testframe"></iframe>
+
+</body>
+</html></html>
diff --git a/dom/base/test/test_mozMatchesSelector.html b/dom/base/test/test_mozMatchesSelector.html
new file mode 100644
index 0000000000..3f163e07a9
--- /dev/null
+++ b/dom/base/test/test_mozMatchesSelector.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Test for legacy mozMatchesSelector</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<div id=test></div>
+<script>
+test(function() {
+ var element = document.getElementById("test");
+ assert_true(element.matches("#test"), "matches");
+ assert_true(element.mozMatchesSelector("#test"), "mozMatchesSelector");
+});
+</script>
diff --git a/dom/base/test/test_mutationobservers.html b/dom/base/test/test_mutationobservers.html
new file mode 100644
index 0000000000..80e42713f7
--- /dev/null
+++ b/dom/base/test/test_mutationobservers.html
@@ -0,0 +1,862 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=641821
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 641821</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=641821">Mozilla Bug 641821</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 641821 **/
+
+SimpleTest.requestFlakyTimeout("requestFlakyTimeout is silly. (But make sure marquee has time to initialize itself.)");
+
+var div = document.createElement("div");
+
+var M;
+if ("MozMutationObserver" in window) {
+ M = window.MozMutationObserver;
+} else if ("WebKitMutationObserver" in window) {
+ M = window.WebKitMutationObserver;
+} else {
+ M = window.MutationObserver;
+}
+
+function log(str) {
+ var d = document.createElement("div");
+ d.textContent = str;
+ if (str.includes("PASSED")) {
+ d.setAttribute("style", "color: green;");
+ } else {
+ d.setAttribute("style", "color: red;");
+ }
+ document.getElementById("log").appendChild(d);
+}
+
+// Some helper functions so that this test runs also outside mochitest.
+if (!("ok" in window)) {
+ window.ok = function(val, str) {
+ log(str + (val ? " PASSED\n" : " FAILED\n"));
+ }
+}
+
+if (!("is" in window)) {
+ window.is = function(val, refVal, str) {
+ log(str + (val == refVal? " PASSED " : " FAILED ") +
+ (val != refVal ? "expected " + refVal + " got " + val + "\n" : "\n"));
+ }
+}
+
+if (!("isnot" in window)) {
+ window.isnot = function(val, refVal, str) {
+ log(str + (val != refVal? " PASSED " : " FAILED ") +
+ (val == refVal ? "Didn't expect " + refVal + "\n" : "\n"));
+ }
+}
+
+if (!("SimpleTest" in window)) {
+ window.SimpleTest =
+ {
+ finish() {
+ document.getElementById("log").appendChild(document.createTextNode("DONE"));
+ },
+ waitForExplicitFinish() {}
+ }
+}
+
+function then(thenFn) {
+ setTimeout(function() {
+ if (thenFn) {
+ setTimeout(thenFn, 0);
+ } else {
+ SimpleTest.finish();
+ }
+ }, 0);
+}
+
+var m;
+var m2;
+var m3;
+var m4;
+
+// Checks normal 'this' handling.
+// Tests also basic attribute handling.
+function runTest() {
+ m = new M(function(records, observer) {
+ is(observer, m, "2nd parameter should be the mutation observer");
+ is(observer, this, "2nd parameter should be 'this'");
+ is(records.length, 1, "Should have one record.");
+ is(records[0].type, "attributes", "Should have got attributes record");
+ is(records[0].target, div, "Should have got div as target");
+ is(records[0].attributeName, "foo", "Should have got record about foo attribute");
+ observer.disconnect();
+ then(testThisBind);
+ m = null;
+ });
+ m.observe(div, { attributes: true, attributeFilter: ["foo"] });
+ div.setAttribute("foo", "bar");
+}
+
+// 'this' handling when fn.bind() is used.
+function testThisBind() {
+ var child = div.appendChild(document.createElement("div"));
+ var gchild = child.appendChild(document.createElement("div"));
+ m = new M((function(records, observer) {
+ is(observer, m, "2nd parameter should be the mutation observer");
+ isnot(observer, this, "2nd parameter should be 'this'");
+ is(records.length, 3, "Should have one record.");
+ is(records[0].type, "attributes", "Should have got attributes record");
+ is(records[0].target, div, "Should have got div as target");
+ is(records[0].attributeName, "foo", "Should have got record about foo attribute");
+ is(records[0].oldValue, "bar", "oldValue should be bar");
+ is(records[1].type, "attributes", "Should have got attributes record");
+ is(records[1].target, div, "Should have got div as target");
+ is(records[1].attributeName, "foo", "Should have got record about foo attribute");
+ is(records[1].oldValue, "bar2", "oldValue should be bar2");
+ is(records[2].type, "attributes", "Should have got attributes record");
+ is(records[2].target, gchild, "Should have got div as target");
+ is(records[2].attributeName, "foo", "Should have got record about foo attribute");
+ is(records[2].oldValue, null, "oldValue should be bar2");
+ observer.disconnect();
+ then(testCharacterData);
+ m = null;
+ }).bind(window));
+ m.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
+ div.setAttribute("foo", "bar2");
+ div.removeAttribute("foo");
+ div.removeChild(child);
+ child.removeChild(gchild);
+ div.appendChild(gchild);
+ div.removeChild(gchild);
+ gchild.setAttribute("foo", "bar");
+}
+
+function testCharacterData() {
+ m = new M(function(records, observer) {
+ is(records[0].type, "characterData", "Should have got characterData");
+ is(records[0].oldValue, null, "Shouldn't have got oldData");
+ observer.disconnect();
+ m = null;
+ });
+ m2 = new M(function(records, observer) {
+ is(records[0].type, "characterData", "Should have got characterData");
+ is(records[0].oldValue, "foo", "Should have got oldData");
+ observer.disconnect();
+ m2 = null;
+ });
+ m3 = new M(function(records, observer) {
+ ok(false, "This should not be called!");
+ observer.disconnect();
+ m3 = null;
+ });
+ m4 = new M(function(records, observer) {
+ is(records[0].oldValue, null, "Shouldn't have got oldData");
+ observer.disconnect();
+ m3.disconnect();
+ m3 = null;
+ then(testChildList);
+ m4 = null;
+ });
+
+ div.appendChild(document.createTextNode("foo"));
+ m.observe(div, { characterData: true, subtree: true });
+ m2.observe(div, { characterData: true, characterDataOldValue: true, subtree: true});
+ // If observing the same node twice, only the latter option should apply.
+ m3.observe(div, { characterData: true, subtree: true });
+ m3.observe(div, { characterData: true, subtree: false });
+ m4.observe(div.firstChild, { characterData: true, subtree: false });
+
+ div.firstChild.data = "bar";
+}
+
+function testChildList() {
+ var fc = div.firstChild;
+ m = new M(function(records, observer) {
+ is(records[0].type, "childList", "Should have got childList");
+ is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
+ is(records[0].removedNodes.length, 1, "Should have got removedNodes");
+ is(records[0].removedNodes[0], fc, "Should have removed a text node");
+ observer.disconnect();
+ then(testChildList2);
+ m = null;
+ });
+ m.observe(div, { childList: true});
+ div.firstChild.remove();
+}
+
+function testChildList2() {
+ div.innerHTML = "<span>1</span><span>2</span>";
+ m = new M(function(records, observer) {
+ is(records[0].type, "childList", "Should have got childList");
+ is(records[0].removedNodes.length, 2, "Should have got removedNodes");
+ is(records[0].addedNodes.length, 1, "Should have got addedNodes");
+ observer.disconnect();
+ then(testChildList3);
+ m = null;
+ });
+ m.observe(div, { childList: true });
+ div.innerHTML = "<span><span>foo</span></span>";
+}
+
+function testChildList3() {
+ m = new M(function(records, observer) {
+ is(records[0].type, "childList", "Should have got childList");
+ is(records[0].removedNodes.length, 1, "Should have got removedNodes");
+ is(records[0].addedNodes.length, 1, "Should have got addedNodes");
+ observer.disconnect();
+ then(testChildList4);
+ m = null;
+ });
+ m.observe(div, { childList: true });
+ div.textContent = "hello";
+}
+
+function testChildList4() {
+ div.textContent = null;
+ var df = document.createDocumentFragment();
+ var t1 = df.appendChild(document.createTextNode("Hello "));
+ var t2 = df.appendChild(document.createTextNode("world!"));
+ var s1 = div.appendChild(document.createElement("span"));
+ s1.textContent = "foo";
+ var s2 = div.appendChild(document.createElement("span"));
+ function callback(records, observer) {
+ is(records.length, 3, "Should have got one record for removing nodes from document fragment and one record for adding them to div");
+ is(records[0].removedNodes.length, 2, "Should have got removedNodes");
+ is(records[0].removedNodes[0], t1, "Should be the 1st textnode");
+ is(records[0].removedNodes[1], t2, "Should be the 2nd textnode");
+ is(records[1].addedNodes.length, 2, "Should have got addedNodes");
+ is(records[1].addedNodes[0], t1, "Should be the 1st textnode");
+ is(records[1].addedNodes[1], t2, "Should be the 2nd textnode");
+ is(records[1].previousSibling, s1, "Should have previousSibling");
+ is(records[1].nextSibling, s2, "Should have nextSibling");
+ is(records[2].type, "characterData", "3rd record should be characterData");
+ is(records[2].target, t1, "target should be the textnode");
+ is(records[2].oldValue, "Hello ", "oldValue was 'Hello '");
+ observer.disconnect();
+ then(testChildList5);
+ m = null;
+ };
+ m = new M(callback);
+ m.observe(df, { childList: true, characterData: true, characterDataOldValue: true, subtree: true });
+ m.observe(div, { childList: true });
+
+ // Make sure transient observers aren't leaked.
+ var leakTest = new M(function(){});
+ leakTest.observe(div, { characterData: true, subtree: true });
+
+ div.insertBefore(df, s2);
+ s1.firstChild.data = "bar"; // This should *not* create a record.
+ t1.data = "Hello the whole "; // This should create a record.
+}
+
+function testChildList5() {
+ div.textContent = null;
+ var c1 = div.appendChild(document.createElement("div"));
+ var c2 = document.createElement("div");
+ var div2 = document.createElement("div");
+ var c3 = div2.appendChild(document.createElement("div"));
+ var c4 = document.createElement("div");
+ var c5 = document.createElement("div");
+ var df = document.createDocumentFragment();
+ var emptyDF = document.createDocumentFragment();
+ var dfc1 = df.appendChild(document.createElement("div"));
+ var dfc2 = df.appendChild(document.createElement("div"));
+ var dfc3 = df.appendChild(document.createElement("div"));
+ m = new M(function(records, observer) {
+ is(records.length, 6 , "");
+ is(records[0].removedNodes.length, 1, "Should have got removedNodes");
+ is(records[0].removedNodes[0], c1, "");
+ is(records[0].addedNodes.length, 1, "Should have got addedNodes");
+ is(records[0].addedNodes[0], c2, "");
+ is(records[0].previousSibling, null, "");
+ is(records[0].nextSibling, null, "");
+ is(records[1].removedNodes.length, 1, "Should have got removedNodes");
+ is(records[1].removedNodes[0], c3, "");
+ is(records[1].addedNodes.length, 0, "Shouldn't have got addedNodes");
+ is(records[1].previousSibling, null, "");
+ is(records[1].nextSibling, null, "");
+ is(records[2].removedNodes.length, 1, "Should have got removedNodes");
+ is(records[2].removedNodes[0], c2, "");
+ is(records[2].addedNodes.length, 1, "Should have got addedNodes");
+ is(records[2].addedNodes[0], c3, "");
+ is(records[2].previousSibling, null, "");
+ is(records[2].nextSibling, null, "");
+ // Check document fragment handling
+ is(records[5].removedNodes.length, 1, "");
+ is(records[5].removedNodes[0], c4, "");
+ is(records[5].addedNodes.length, 3, "");
+ is(records[5].addedNodes[0], dfc1, "");
+ is(records[5].addedNodes[1], dfc2, "");
+ is(records[5].addedNodes[2], dfc3, "");
+ is(records[5].previousSibling, c3, "");
+ is(records[5].nextSibling, c5, "");
+ observer.disconnect();
+ then(testNestedMutations);
+ m = null;
+ });
+ m.observe(div, { childList: true, subtree: true });
+ m.observe(div2, { childList: true, subtree: true });
+ div.replaceChild(c2, c1);
+ div.replaceChild(c3, c2);
+ div.appendChild(c4);
+ div.appendChild(c5);
+ div.replaceChild(df, c4);
+ div.appendChild(emptyDF); // empty document shouldn't cause mutation records
+}
+
+function testNestedMutations() {
+ div.textContent = null;
+ div.appendChild(document.createTextNode("foo"));
+ var m2WasCalled = false;
+ m = new M(function(records, observer) {
+ is(records[0].type, "characterData", "Should have got characterData");
+ observer.disconnect();
+ m = null;
+ m3 = new M(function(recordsInner, observerInnder) {
+ ok(m2WasCalled, "m2 should have been called before m3!");
+ is(recordsInner[0].type, "characterData", "Should have got characterData");
+ observerInnder.disconnect();
+ then(testAdoptNode);
+ m3 = null;
+ });
+ m3.observe(div, { characterData: true, subtree: true});
+ div.firstChild.data = "foo";
+ });
+ m2 = new M(function(records, observer) {
+ m2WasCalled = true;
+ is(records[0].type, "characterData", "Should have got characterData");
+ observer.disconnect();
+ m2 = null;
+ });
+ m2.observe(div, { characterData: true, subtree: true});
+ div.appendChild(document.createTextNode("foo"));
+ m.observe(div, { characterData: true, subtree: true });
+
+ div.firstChild.data = "bar";
+}
+
+function testAdoptNode() {
+ var d1 = document.implementation.createHTMLDocument(null);
+ var d2 = document.implementation.createHTMLDocument(null);
+ var addedNode;
+ m = new M(function(records, observer) {
+ is(records.length, 3, "Should have 2 records");
+ is(records[0].target.ownerDocument, d1, "ownerDocument should be the initial document")
+ is(records[1].target.ownerDocument, d2, "ownerDocument should be the new document");
+ is(records[2].type, "attributes", "Should have got attribute mutation")
+ is(records[2].attributeName, "foo", "Should have got foo attribute mutation")
+ observer.disconnect();
+ then(testOuterHTML);
+ m = null;
+ });
+ m.observe(d1, { childList: true, subtree: true, attributes: true });
+ d2.body.appendChild(d1.body);
+ addedNode = d2.body.lastChild.appendChild(d2.createElement("div"));
+ addedNode.setAttribute("foo", "bar");
+}
+
+function testOuterHTML() {
+ var doc = document.implementation.createHTMLDocument(null);
+ var d1 = doc.body.appendChild(document.createElement("div"));
+ var d2 = doc.body.appendChild(document.createElement("div"));
+ var d3 = doc.body.appendChild(document.createElement("div"));
+ var d4 = doc.body.appendChild(document.createElement("div"));
+ m = new M(function(records, observer) {
+ is(records.length, 4, "Should have 1 record");
+ is(records[0].removedNodes.length, 1, "Should have 1 removed nodes");
+ is(records[0].addedNodes.length, 2, "Should have 2 added nodes");
+ is(records[0].previousSibling, null, "");
+ is(records[0].nextSibling, d2, "");
+ is(records[1].removedNodes.length, 1, "Should have 1 removed nodes");
+ is(records[1].addedNodes.length, 2, "Should have 2 added nodes");
+ is(records[1].previousSibling, records[0].addedNodes[1], "");
+ is(records[1].nextSibling, d3, "");
+ is(records[2].removedNodes.length, 1, "Should have 1 removed nodes");
+ is(records[2].addedNodes.length, 2, "Should have 2 added nodes");
+ is(records[2].previousSibling, records[1].addedNodes[1], "");
+ is(records[2].nextSibling, d4, "");
+ is(records[3].removedNodes.length, 1, "Should have 1 removed nodes");
+ is(records[3].addedNodes.length, 0);
+ is(records[3].previousSibling, records[2].addedNodes[1], "");
+ is(records[3].nextSibling, null, "");
+ observer.disconnect();
+ then(testInsertAdjacentHTML);
+ m = null;
+ });
+ m.observe(doc, { childList: true, subtree: true });
+ d1.outerHTML = "<div>1</div><div>1</div>";
+ d2.outerHTML = "<div>2</div><div>2</div>";
+ d3.outerHTML = "<div>3</div><div>3</div>";
+ d4.outerHTML = "";
+}
+
+function testInsertAdjacentHTML() {
+ var doc = document.implementation.createHTMLDocument(null);
+ var d1 = doc.body.appendChild(document.createElement("div"));
+ var d2 = doc.body.appendChild(document.createElement("div"));
+ var d3 = doc.body.appendChild(document.createElement("div"));
+ var d4 = doc.body.appendChild(document.createElement("div"));
+ m = new M(function(records, observer) {
+ is(records.length, 4, "");
+ is(records[0].target, doc.body, "");
+ is(records[0].previousSibling, null, "");
+ is(records[0].nextSibling, d1, "");
+ is(records[1].target, d2, "");
+ is(records[1].previousSibling, null, "");
+ is(records[1].nextSibling, null, "");
+ is(records[2].target, d3, "");
+ is(records[2].previousSibling, null, "");
+ is(records[2].nextSibling, null, "");
+ is(records[3].target, doc.body, "");
+ is(records[3].previousSibling, d4, "");
+ is(records[3].nextSibling, null, "");
+ observer.disconnect();
+ then(testSyncXHR);
+ m = null;
+ });
+ m.observe(doc, { childList: true, subtree: true });
+ d1.insertAdjacentHTML("beforebegin", "<div></div><div></div>");
+ d2.insertAdjacentHTML("afterbegin", "<div></div><div></div>");
+ d3.insertAdjacentHTML("beforeend", "<div></div><div></div>");
+ d4.insertAdjacentHTML("afterend", "<div></div><div></div>");
+}
+
+
+var callbackHandled = false;
+
+function testSyncXHR() {
+ div.textContent = null;
+ m = new M(function(records, observer) {
+ is(records.length, 1, "");
+ is(records[0].addedNodes.length, 1, "");
+ callbackHandled = true;
+ observer.disconnect();
+ m = null;
+ });
+ m.observe(div, { childList: true, subtree: true });
+ div.innerHTML = "<div>hello</div>";
+ var x = new XMLHttpRequest();
+ x.open("GET", window.location, false);
+ x.send();
+ ok(!callbackHandled, "Shouldn't have called the mutation callback!");
+ setTimeout(testSyncXHR2, 0);
+}
+
+function testSyncXHR2() {
+ ok(callbackHandled, "Should have called the mutation callback!");
+ then(testTakeRecords);
+}
+
+function testTakeRecords() {
+ var s = "<span>1</span><span>2</span>";
+ div.innerHTML = s;
+ var takenRecords;
+ m = new M(function(records, observer) {
+ is(records.length, 3, "Should have got 3 records");
+
+ is(records[0].type, "attributes", "Should have got attributes");
+ is(records[0].attributeName, "foo", "");
+ is(records[0].attributeNamespace, null, "");
+ is(records[0].prevValue, null, "");
+ is(records[1].type, "childList", "Should have got childList");
+ is(records[1].removedNodes.length, 2, "Should have got removedNodes");
+ is(records[1].addedNodes.length, 2, "Should have got addedNodes");
+ is(records[2].type, "attributes", "Should have got attributes");
+ is(records[2].attributeName, "foo", "");
+
+ is(records.length, takenRecords.length, "Should have had similar mutations");
+ is(records[0].type, takenRecords[0].type, "Should have had similar mutations");
+ is(records[1].type, takenRecords[1].type, "Should have had similar mutations");
+ is(records[2].type, takenRecords[2].type, "Should have had similar mutations");
+
+ is(records[1].removedNodes.length, takenRecords[1].removedNodes.length, "Should have had similar mutations");
+ is(records[1].addedNodes.length, takenRecords[1].addedNodes.length, "Should have had similar mutations");
+
+ is(m.takeRecords().length, 0, "Shouldn't have any records");
+ observer.disconnect();
+ then(testMutationObserverAndEvents);
+ m = null;
+ });
+ m.observe(div, { childList: true, attributes: true });
+ div.setAttribute("foo", "bar");
+ div.innerHTML = s;
+ div.removeAttribute("foo");
+ takenRecords = m.takeRecords();
+ div.setAttribute("foo", "bar");
+ div.innerHTML = s;
+ div.removeAttribute("foo");
+}
+
+function testTakeRecords() {
+ function mutationListener(e) {
+ ++mutationEventCount;
+ is(e.attrChange, MutationEvent.ADDITION, "unexpected change");
+ }
+
+ m = new M(function(records, observer) {
+ is(records.length, 2, "Should have got 2 records");
+ is(records[0].type, "attributes", "Should have got attributes");
+ is(records[0].attributeName, "foo", "");
+ is(records[0].oldValue, null, "");
+ is(records[1].type, "attributes", "Should have got attributes");
+ is(records[1].attributeName, "foo", "");
+ is(records[1].oldValue, "bar", "");
+ observer.disconnect();
+ div.removeEventListener("DOMAttrModified", mutationListener);
+ then(testExpandos);
+ m = null;
+ });
+ m.observe(div, { attributes: true, attributeOldValue: true });
+ var mutationEventCount = 0;
+ div.addEventListener("DOMAttrModified", mutationListener);
+ div.setAttribute("foo", "bar");
+ div.setAttribute("foo", "bar");
+ is(mutationEventCount, 1, "Should have got only one mutation event!");
+}
+
+function testExpandos() {
+ m2 = new M(function(records, observer) {
+ is(observer.expandoProperty, true);
+ observer.disconnect();
+ then(testOutsideShadowDOM);
+ });
+ m2.expandoProperty = true;
+ m2.observe(div, { attributes: true });
+ m2 = null;
+ if (SpecialPowers) {
+ // Run GC several times to see if the expando property disappears.
+
+ SpecialPowers.gc();
+ SpecialPowers.gc();
+ SpecialPowers.gc();
+ SpecialPowers.gc();
+ }
+ div.setAttribute("foo", "bar2");
+}
+
+function testOutsideShadowDOM() {
+ if (!div.attachShadow) {
+ todo(false, "Skipping testOutsideShadowDOM and testInsideShadowDOM " +
+ "because attachShadow is not supported");
+ then(testMarquee);
+ return;
+ }
+ m = new M(function(records, observer) {
+ is(records.length, 1);
+ is(records[0].type, "attributes", "Should have got attributes");
+ observer.disconnect();
+ then(testMarquee);
+ });
+ m.observe(div, {
+ attributes: true,
+ childList: true,
+ characterData: true,
+ subtree: true
+ })
+ var sr = div.attachShadow({ mode: "open" });
+ sr.innerHTML = "<div" + ">text</" + "div>";
+ sr.firstChild.setAttribute("foo", "bar");
+ sr.firstChild.firstChild.data = "text2";
+ sr.firstChild.appendChild(document.createElement("div"));
+ div.setAttribute("foo", "bar");
+}
+
+function testMarquee() {
+ m = new M(function(records, observer) {
+ is(records.length, 1);
+ is(records[0].type, "attributes");
+ is(records[0].attributeName, "ok");
+ is(records[0].oldValue, null);
+ observer.disconnect();
+ then(testStyleCreate);
+ });
+ var marquee = document.createElement("marquee");
+ m.observe(marquee, {
+ attributes: true,
+ attributeOldValue: true,
+ childList: true,
+ characterData: true,
+ subtree: true
+ });
+ document.body.appendChild(marquee);
+ setTimeout(function() {marquee.setAttribute("ok", "ok")}, 500);
+}
+
+function testStyleCreate() {
+ m = new M(function(records, observer) {
+ is(records.length, 1, "number of records");
+ is(records[0].type, "attributes", "record.type");
+ is(records[0].attributeName, "style", "record.attributeName");
+ is(records[0].oldValue, null, "record.oldValue");
+ isnot(div.getAttribute("style"), null, "style attribute after creation");
+ observer.disconnect();
+ m = null;
+ div.removeAttribute("style");
+ then(testStyleModify);
+ });
+ m.observe(div, { attributes: true, attributeOldValue: true });
+ is(div.getAttribute("style"), null, "style attribute before creation");
+ div.style.color = "blue";
+}
+
+function testStyleModify() {
+ div.style.color = "yellow";
+ m = new M(function(records, observer) {
+ is(records.length, 1, "number of records");
+ is(records[0].type, "attributes", "record.type");
+ is(records[0].attributeName, "style", "record.attributeName");
+ isnot(div.getAttribute("style"), null, "style attribute after modification");
+ observer.disconnect();
+ m = null;
+ div.removeAttribute("style");
+ then(testStyleRead);
+ });
+ m.observe(div, { attributes: true });
+ isnot(div.getAttribute("style"), null, "style attribute before modification");
+ div.style.color = "blue";
+}
+
+function testStyleRead() {
+ m = new M(function(records, observer) {
+ is(records.length, 1, "number of records");
+ is(records[0].type, "attributes", "record.type");
+ is(records[0].attributeName, "data-test", "record.attributeName");
+ is(div.getAttribute("style"), null, "style attribute after read");
+ observer.disconnect();
+ div.removeAttribute("data-test");
+ m = null;
+ then(testStyleRemoveProperty);
+ });
+ m.observe(div, { attributes: true });
+ is(div.getAttribute("style"), null, "style attribute before read");
+ var value = div.style.color; // shouldn't generate any mutation records
+ div.setAttribute("data-test", "a");
+}
+
+function testStyleRemoveProperty() {
+ div.style.color = "blue";
+ m = new M(function(records, observer) {
+ is(records.length, 1, "number of records");
+ is(records[0].type, "attributes", "record.type");
+ is(records[0].attributeName, "style", "record.attributeName");
+ isnot(div.getAttribute("style"), null, "style attribute after successful removeProperty");
+ observer.disconnect();
+ m = null;
+ div.removeAttribute("style");
+ then(testStyleRemoveProperty2);
+ });
+ m.observe(div, { attributes: true });
+ isnot(div.getAttribute("style"), null, "style attribute before successful removeProperty");
+ div.style.removeProperty("color");
+}
+
+function testStyleRemoveProperty2() {
+ m = new M(function(records, observer) {
+ is(records.length, 1, "number of records");
+ is(records[0].type, "attributes", "record.type");
+ is(records[0].attributeName, "data-test", "record.attributeName");
+ is(div.getAttribute("style"), null, "style attribute after unsuccessful removeProperty");
+ observer.disconnect();
+ m = null;
+ div.removeAttribute("data-test");
+ then(testAttributeRecordMerging1);
+ });
+ m.observe(div, { attributes: true });
+ is(div.getAttribute("style"), null, "style attribute before unsuccessful removeProperty");
+ div.style.removeProperty("color"); // shouldn't generate any mutation records
+ div.setAttribute("data-test", "a");
+}
+
+function testAttributeRecordMerging1() {
+ ok(true, "testAttributeRecordMerging1");
+ m = new M(function(records, observer) {
+ is(records.length, 2);
+ is(records[0].type, "attributes");
+ is(records[0].target, div);
+ is(records[0].attributeName, "foo");
+ is(records[0].attributeNamespace, null);
+ is(records[0].oldValue, null);
+
+ is(records[1].type, "attributes");
+ is(records[1].target, div.firstChild);
+ is(records[1].attributeName, "foo");
+ is(records[1].attributeNamespace, null);
+ is(records[1].oldValue, null);
+ observer.disconnect();
+ div.innerHTML = "";
+ div.removeAttribute("foo");
+ then(testAttributeRecordMerging2);
+ });
+ m.observe(div, {
+ attributes: true,
+ subtree: true
+ });
+ SpecialPowers.wrap(m).mergeAttributeRecords = true;
+
+ div.setAttribute("foo", "bar_1");
+ div.setAttribute("foo", "bar_2");
+ div.innerHTML = "<div></div>";
+ div.firstChild.setAttribute("foo", "bar_1");
+ div.firstChild.setAttribute("foo", "bar_2");
+}
+
+function testAttributeRecordMerging2() {
+ ok(true, "testAttributeRecordMerging2");
+ m = new M(function(records, observer) {
+ is(records.length, 2);
+ is(records[0].type, "attributes");
+ is(records[0].target, div);
+ is(records[0].attributeName, "foo");
+ is(records[0].attributeNamespace, null);
+ is(records[0].oldValue, "initial");
+
+ is(records[1].type, "attributes");
+ is(records[1].target, div.firstChild);
+ is(records[1].attributeName, "foo");
+ is(records[1].attributeNamespace, null);
+ is(records[1].oldValue, "initial");
+ observer.disconnect();
+ div.innerHTML = "";
+ div.removeAttribute("foo");
+ then(testAttributeRecordMerging3);
+ });
+
+ div.setAttribute("foo", "initial");
+ div.innerHTML = "<div></div>";
+ div.firstChild.setAttribute("foo", "initial");
+ m.observe(div, {
+ attributes: true,
+ subtree: true,
+ attributeOldValue: true
+ });
+ SpecialPowers.wrap(m).mergeAttributeRecords = true;
+
+ div.setAttribute("foo", "bar_1");
+ div.setAttribute("foo", "bar_2");
+ div.firstChild.setAttribute("foo", "bar_1");
+ div.firstChild.setAttribute("foo", "bar_2");
+}
+
+function testAttributeRecordMerging3() {
+ ok(true, "testAttributeRecordMerging3");
+ m = new M(function(records, observer) {
+ is(records.length, 4);
+ is(records[0].type, "attributes");
+ is(records[0].target, div);
+ is(records[0].attributeName, "foo");
+ is(records[0].attributeNamespace, null);
+ is(records[0].oldValue, "initial");
+
+ is(records[1].type, "attributes");
+ is(records[1].target, div.firstChild);
+ is(records[1].attributeName, "foo");
+ is(records[1].attributeNamespace, null);
+ is(records[1].oldValue, "initial");
+
+ is(records[2].type, "attributes");
+ is(records[2].target, div);
+ is(records[2].attributeName, "foo");
+ is(records[2].attributeNamespace, null);
+ is(records[2].oldValue, "bar_1");
+
+ is(records[3].type, "attributes");
+ is(records[3].target, div.firstChild);
+ is(records[3].attributeName, "foo");
+ is(records[3].attributeNamespace, null);
+ is(records[3].oldValue, "bar_1");
+
+ observer.disconnect();
+ div.innerHTML = "";
+ div.removeAttribute("foo");
+ then(testAttributeRecordMerging4);
+ });
+
+ div.setAttribute("foo", "initial");
+ div.innerHTML = "<div></div>";
+ div.firstChild.setAttribute("foo", "initial");
+ m.observe(div, {
+ attributes: true,
+ subtree: true,
+ attributeOldValue: true
+ });
+ SpecialPowers.wrap(m).mergeAttributeRecords = true;
+
+ // No merging should happen.
+ div.setAttribute("foo", "bar_1");
+ div.firstChild.setAttribute("foo", "bar_1");
+ div.setAttribute("foo", "bar_2");
+ div.firstChild.setAttribute("foo", "bar_2");
+}
+
+function testAttributeRecordMerging4() {
+ ok(true, "testAttributeRecordMerging4");
+ m = new M(function(records, observer) {
+ });
+
+ div.setAttribute("foo", "initial");
+ div.innerHTML = "<div></div>";
+ div.firstChild.setAttribute("foo", "initial");
+ m.observe(div, {
+ attributes: true,
+ subtree: true,
+ attributeOldValue: true
+ });
+ SpecialPowers.wrap(m).mergeAttributeRecords = true;
+
+ div.setAttribute("foo", "bar_1");
+ div.setAttribute("foo", "bar_2");
+ div.firstChild.setAttribute("foo", "bar_1");
+ div.firstChild.setAttribute("foo", "bar_2");
+
+ var records = m.takeRecords();
+
+ is(records.length, 2);
+ is(records[0].type, "attributes");
+ is(records[0].target, div);
+ is(records[0].attributeName, "foo");
+ is(records[0].attributeNamespace, null);
+ is(records[0].oldValue, "initial");
+
+ is(records[1].type, "attributes");
+ is(records[1].target, div.firstChild);
+ is(records[1].attributeName, "foo");
+ is(records[1].attributeNamespace, null);
+ is(records[1].oldValue, "initial");
+ m.disconnect();
+ div.innerHTML = "";
+ div.removeAttribute("foo");
+ then(testChromeOnly);
+}
+
+function testChromeOnly() {
+ // Content can't access chromeOnlyNodes
+ try {
+ var mo = new M(function(records, observer) { });
+ mo.observe(div, { chromeOnlyNodes: true });
+ ok(false, "Should have thrown when trying to observe with chrome-only init");
+ } catch (e) {
+ ok(true, "Throws when trying to observe with chrome-only init");
+ }
+
+ then();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div id="log">
+</div>
+</body>
+</html>
diff --git a/dom/base/test/test_named_frames.html b/dom/base/test/test_named_frames.html
new file mode 100644
index 0000000000..675a36e0cf
--- /dev/null
+++ b/dom/base/test/test_named_frames.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=823227
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 823227</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 823227 **/
+
+ SimpleTest.waitForExplicitFinish();
+ function doTest() {
+ is(frames[0].foo, frames[0][0],
+ "Should be able to look up frames by name in SVG documents");
+ is(frames[1].foo, frames[1][0],
+ "Should be able to look up frames by name in XML documents");
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(doTest);
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=823227">Mozilla Bug 823227</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject><iframe name='foo' id='foo' xmlns='http://www.w3.org/1999/xhtml'/></foreignObject></svg>"></iframe>
+<iframe src="data:text/xml,<root><iframe name='foo' id='foo' xmlns='http://www.w3.org/1999/xhtml'/></root>"></iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_navigatorPrefOverride.html b/dom/base/test/test_navigatorPrefOverride.html
new file mode 100644
index 0000000000..478b14e791
--- /dev/null
+++ b/dom/base/test/test_navigatorPrefOverride.html
@@ -0,0 +1,54 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for navigator property override</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"></pre>
+<script class="testbody" type="text/javascript">
+
+ ok(navigator.appName, "This is used just to populate the cache");
+ ok(navigator.appVersion, "This is used just to populate the cache");
+
+ // B2G could have an empty platform.
+ info(navigator.platform);
+
+ ok(navigator.userAgent, "This is used just to populate the cache");
+
+ SpecialPowers.pushPrefEnv({"set": [
+ ["general.appname.override", "appName overridden"],
+ ["general.appversion.override", "appVersion overridden"],
+ ["general.platform.override", "platform overridden"],
+ ["general.useragent.override", "userAgent overridden"],
+ ]},
+ function() {
+ var ifr = document.createElement('IFRAME');
+ ifr.src = "about:blank";
+
+ ifr.addEventListener('load', function() {
+ var nav = ifr.contentWindow.navigator;
+ isnot(navigator.appName, nav.appName, "appName should match");
+ isnot(navigator.appVersion, nav.appVersion, "appVersion should match");
+ isnot(navigator.platform, nav.platform, "platform should match");
+ isnot(navigator.userAgent, nav.userAgent, "userAgent should match");
+ SimpleTest.finish();
+ });
+
+ document.getElementById('content').appendChild(ifr);
+ }
+ );
+
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_navigator_cookieEnabled.html b/dom/base/test/test_navigator_cookieEnabled.html
new file mode 100644
index 0000000000..1935e9024c
--- /dev/null
+++ b/dom/base/test/test_navigator_cookieEnabled.html
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1753586
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Navigator.cookieEnabled</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ "use strict";
+
+ /** Test for Bug 1753586 **/
+
+ const BEHAVIOR_REJECT = 2;
+ const BEHAVIOR_REJECT_TRACKER = 4;
+ const BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN = 5;
+
+ const TESTS = [
+ { cookieBehavior: BEHAVIOR_REJECT, expect: false },
+ { cookieBehavior: BEHAVIOR_REJECT_TRACKER, expect: true },
+ {
+ cookieBehavior: BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
+ expect: true,
+ },
+ ];
+
+ SimpleTest.waitForExplicitFinish();
+
+ function createAndWaitIframeLoading(win, src, sandbox) {
+ return new Promise(resolve => {
+ let iframe = win.document.createElement("iframe");
+
+ iframe.addEventListener(
+ "load",
+ () => resolve(iframe),
+ { once: true }
+ );
+
+ win.document.body.appendChild(iframe);
+ if (sandbox) {
+ iframe.sandbox = sandbox;
+ }
+ iframe.src = src;
+ });
+ }
+
+ async function runTestInAnotherWindow(expect) {
+ let win = window.open();
+
+ is(
+ win.navigator.cookieEnabled,
+ expect,
+ `Navigator.cookieEnabled returns expected value in first-party context.`
+ );
+
+ // Create a first-party iframe and check if navigator.cookieEnabled is
+ // expected.
+ let iframe = await createAndWaitIframeLoading(
+ win,
+ "http://mochi.test:8888/"
+ );
+
+ await SpecialPowers.spawn(iframe, [expect], value => {
+ is(
+ content.navigator.cookieEnabled,
+ value,
+ "Navigator.cookieEnabled returns expected value in first-party iframe."
+ );
+ });
+
+ // Create a third-party iframe and check if navigator.cookieEnabled is
+ // expected.
+ iframe = await createAndWaitIframeLoading(
+ win,
+ "http://example.com/"
+ );
+
+ await SpecialPowers.spawn(iframe, [expect], value => {
+ is(
+ content.navigator.cookieEnabled,
+ value,
+ "Navigator.cookieEnabled returns expected value in third-party iframe."
+ );
+ });
+
+ // Create a sandboxed iframe and check if navigator.cookieEnabled is
+ // expected. It should still return true even if setting cookies in
+ // sandboxed iframe will throw a security error.
+ iframe = await createAndWaitIframeLoading(
+ win,
+ "http://mochi.test:8888/",
+ "allow-scripts"
+ );
+
+ await SpecialPowers.spawn(iframe, [expect], value => {
+ is(
+ content.navigator.cookieEnabled,
+ value,
+ "Navigator.cookieEnabled returns expected value in sandboxed iframe."
+ );
+ });
+
+ win.close();
+ }
+
+ add_task(async function doTests() {
+ for (let test of TESTS) {
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["network.cookie.cookieBehavior", test.cookieBehavior],
+ ]});
+
+ // We need to run the test in another window so that the cookieBehavior
+ // setting would take effect.
+ await runTestInAnotherWindow(test.expect);
+ }
+ });
+
+ </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/base/test/test_navigator_hardwareConcurrency.html b/dom/base/test/test_navigator_hardwareConcurrency.html
new file mode 100644
index 0000000000..9b201d4f31
--- /dev/null
+++ b/dom/base/test/test_navigator_hardwareConcurrency.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Navigator.hardwareConcurrency</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ "use strict";
+
+ function resistFingerprinting(value) {
+ return SpecialPowers.pushPrefEnv({"set": [["privacy.resistFingerprinting", value]]});
+ }
+
+ var x = navigator.hardwareConcurrency;
+ is(typeof x, "number", "hardwareConcurrency should be a number.");
+ ok(x > 0, "hardwareConcurrency should be greater than 0.");
+
+ SimpleTest.waitForExplicitFinish();
+
+ resistFingerprinting(true).then(() => {
+ const y = navigator.hardwareConcurrency;
+ ok(y === 2, "hardwareConcurrency should always be 2 when we're resisting fingerprinting.");
+
+ resistFingerprinting(false).then(() => {
+ const z = navigator.hardwareConcurrency;
+ ok(z === x, "hardwareConcurrency should be the same as before we were resisting fingerprinting.");
+ SimpleTest.finish();
+ });
+ });
+
+ </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_navigator_language.html b/dom/base/test/test_navigator_language.html
new file mode 100644
index 0000000000..4fc7e47865
--- /dev/null
+++ b/dom/base/test/test_navigator_language.html
@@ -0,0 +1,213 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=889335
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for NavigatorLanguage</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=889335">Mozilla Bug 889335</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+<script type="application/javascript">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+
+ /** Test for NavigatorLanguage **/
+ var actualLanguageChangesFromHandler = 0;
+ var actualLanguageChangesFromAVL = 0;
+ var expectedLanguageChanges = 0;
+ var emptyLocale = SpecialPowers.Services.locale.webExposedLocales[0];
+
+ var testValues = [
+ { accept_languages: 'foo', language: 'foo', languages: ['foo'] },
+ { accept_languages: '', language: emptyLocale, languages: [emptyLocale] },
+ { accept_languages: 'foo,bar', language: 'foo', languages: [ 'foo', 'bar' ] },
+ { accept_languages: ' foo , bar ', language: 'foo', languages: [ 'foo', 'bar' ] },
+ { accept_languages: ' foo ; bar ', language: 'foo ; bar', languages: [ 'foo ; bar' ] },
+ { accept_languages: '_foo_', language: '_foo_', languages: ['_foo_'] },
+ { accept_languages: 'en_', language: 'en-', languages: ['en-'] },
+ { accept_languages: 'en__', language: 'en-_', languages: ['en-_'] },
+ { accept_languages: 'en_US, fr_FR', language: 'en-US', languages: ['en-US', 'fr-FR'] },
+ { accept_languages: 'en_US_CA', language: 'en-US_CA', languages: ['en-US_CA'] },
+ { accept_languages: 'en_us-ca', language: 'en-US-CA', languages: ['en-US-CA'] },
+ { accept_languages: 'en_us-cal, en_us-c', language: 'en-US-cal', languages: ['en-US-cal', 'en-US-c'] },
+ ];
+
+ var currentTestIdx = 0;
+ var tests = [];
+ function nextTest() {
+ currentTestIdx++;
+ if (currentTestIdx >= tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ tests[currentTestIdx]();
+ }
+
+ // Check that the API is there.
+ tests.push(function testAPIPresence() {
+ ok('language' in window.navigator);
+ ok('languages' in window.navigator);
+ ok('onlanguagechange' in window);
+
+ nextTest();
+ });
+
+ // Check that calling navigator.languages return the same array, unless there
+ // was a change.
+ tests.push(function testArrayCached() {
+ var previous = navigator.languages;
+ is(navigator.languages, navigator.languages, "navigator.languages is cached");
+ is(navigator.languages, previous, "navigator.languages is cached");
+
+ window.onlanguagechange = function() {
+ isnot(navigator.languages, previous, "navigator.languages cached value was updated");
+ window.onlanguagechange = null;
+
+ nextTest();
+ }
+
+ setTimeout(function() {
+ SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', 'testArrayCached']]});
+ }, 0);
+ });
+
+ // Test that event handler inside the <body> works as expected and that the
+ // event has the expected properties.
+ tests.push(function testEventProperties() {
+ document.body.setAttribute('onlanguagechange',
+ "document.body.removeAttribute('onlanguagechange');" +
+ "is(event.cancelable, false); is(event.bubbles, false);" +
+ "nextTest();");
+
+ setTimeout(function() {
+ SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', 'testEventProperties']]}, function() {});
+ }, 0);
+ });
+
+ // Check that the returned values such as the behavior when the underlying
+ // languages change.
+ tests.push(function testBasicBehaviour() {
+ function checkIfDoneAndProceed() {
+ if (actualLanguageChangesFromHandler == actualLanguageChangesFromAVL) {
+ if (genEvents.next().done) {
+ window.onlanguagechange = null;
+ window.removeEventListener('languagechange', languageChangeAVL);
+ nextTest();
+ }
+ }
+ }
+ window.onlanguagechange = function() {
+ actualLanguageChangesFromHandler++;
+ checkIfDoneAndProceed();
+ }
+ function languageChangeAVL() {
+ actualLanguageChangesFromAVL++;
+ checkIfDoneAndProceed();
+ }
+ window.addEventListener('languagechange', languageChangeAVL);
+
+ function* testEvents() {
+ for (var i = 0; i < testValues.length; ++i) {
+ var data = testValues[i];
+ setTimeout(function(d) {
+ SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', d.accept_languages]]});
+ }, 0, data);
+ expectedLanguageChanges++;
+ yield undefined;
+
+ is(actualLanguageChangesFromAVL, expectedLanguageChanges);
+ is(actualLanguageChangesFromHandler, expectedLanguageChanges);
+
+ is(navigator.language, data.language);
+ is(navigator.languages.length, data.languages.length);
+ if (navigator.languages.length) {
+ is(navigator.languages[0], navigator.language)
+ }
+ for (var j = 0; j < navigator.languages.length; ++j) {
+ is(navigator.languages[j], data.languages[j]);
+ }
+ }
+ }
+
+ var genEvents = testEvents();
+ genEvents.next();
+ });
+
+ // Check that the languagechange event isn't sent twice if the preference
+ // is set to the same value.
+ tests.push(function testOnlyFireIfRealChange() {
+ function* changeLanguage() {
+ setTimeout(function() {
+ SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', 'fr-CA']]});
+ });
+ yield undefined;
+
+ setTimeout(function() {
+ // Twice the same change, should fire only one event.
+ SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', 'fr-CA']]});
+ setTimeout(function() {
+ // A real change to tell the test it should now count how many changes were
+ // received until now.
+ SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', 'fr-FR']]});
+ });
+ });
+ yield undefined;
+ }
+
+ var genChanges = changeLanguage();
+
+ var doubleEventCount = 0;
+ window.onlanguagechange = function() {
+ if (navigator.language == 'fr-FR') {
+ is(1, doubleEventCount);
+ window.onlanguagechange = null;
+ nextTest();
+ return;
+ }
+
+ if (navigator.language == 'fr-CA') {
+ doubleEventCount++;
+ }
+ genChanges.next();
+ }
+
+ genChanges.next();
+ });
+
+ // Check that there is no crash when a change happen after a window listening
+ // to them is killed.
+ tests.push(function testThatAddingAnEventDoesNotHaveSideEffects() {
+ var frame = document.createElement('iframe');
+ frame.srcdoc = '<script>window.onlanguagechange=function(){}<\/script>';
+ document.body.appendChild(frame);
+
+ frame.contentWindow.onload = function() {
+ document.body.removeChild(frame);
+ frame = null;
+
+ SpecialPowers.exactGC(function() {
+ // This should not crash.
+ SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', 'en-GB']]}, nextTest);
+ });
+ }
+ });
+
+ // There is one test using document.body.
+ addLoadEvent(function() {
+ tests[0]();
+ });
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_navigator_resolve_identity_xrays.xhtml b/dom/base/test/test_navigator_resolve_identity_xrays.xhtml
new file mode 100644
index 0000000000..b4e0632bac
--- /dev/null
+++ b/dom/base/test/test_navigator_resolve_identity_xrays.xhtml
@@ -0,0 +1,39 @@
+<?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=985827
+-->
+<window title="Mozilla Bug 985827"
+ 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=985827"
+ target="_blank">Mozilla Bug 985827</a>
+ <iframe id="t"></iframe>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 985827 **/
+
+ SimpleTest.waitForExplicitFinish();
+
+ addLoadEvent(function() {
+ var iframe = document.getElementById("t");
+
+ var dir = "chrome://mochitests/content/chrome/dom/base/test/";
+ iframe.src = dir + "file_navigator_resolve_identity_xrays.xhtml";
+ iframe.onload = function() { finish(); };
+
+ function finish() {
+ SimpleTest.finish();
+ }
+ });
+
+ ]]>
+ </script>
+</window>
diff --git a/dom/base/test/test_nested_event_loop_spin_and_idle_tasks.html b/dom/base/test/test_nested_event_loop_spin_and_idle_tasks.html
new file mode 100644
index 0000000000..940e22527c
--- /dev/null
+++ b/dom/base/test/test_nested_event_loop_spin_and_idle_tasks.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Nested event loop spinning and idle task handling</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ if (!location.search.includes("newpage")) {
+ SimpleTest.waitForExplicitFinish();
+ var win = window.open(this.location + "?newpage");
+ win.onload = function() {
+ var xhr = new XMLHttpRequest();
+ // Spin the event loop using a synchronous XMLHttpRequest.
+ xhr.open("GET", "slow.sjs", false);
+ xhr.send();
+ ok(win.didRunIdleCallback, "Should have run an idle callback.");
+ win.close();
+ SimpleTest.finish();
+ }
+ } else {
+ var didRunIdleCallback = false;
+ requestIdleCallback(function() {
+ didRunIdleCallback = true;
+ });
+ }
+ </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_nodelist_holes.html b/dom/base/test/test_nodelist_holes.html
new file mode 100644
index 0000000000..0f69776d0b
--- /dev/null
+++ b/dom/base/test/test_nodelist_holes.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=699826
+-->
+<head>
+ <title>Test for Bug 699826</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=699826">Mozilla Bug 699826</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 699826 **/
+HTMLCollection.prototype[0] = "PASSProto0";
+HTMLCollection.prototype[1] = "PASSProto1";
+var list = document.getElementsByTagName("testtag");
+is(list[0], "PASSProto0", "Should expose proto properties on the list");
+is(list[1], "PASSProto1", "Should expose more proto properties on the list");
+
+var testtag = document.createElement("testtag");
+
+document.body.appendChild(testtag);
+
+is(list[0], testtag, "Should expose elements in the list");
+is(list[1], "PASSProto1", "Should expose proto properties out of range on the list");
+
+testtag.remove();
+
+is(list[0], "PASSProto0", "Should expose proto properties on the list after removal");
+is(list[1], "PASSProto1", "Should expose more proto properties on the list after removal");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_openDialogChromeOnly.html b/dom/base/test/test_openDialogChromeOnly.html
new file mode 100644
index 0000000000..7902554e2b
--- /dev/null
+++ b/dom/base/test/test_openDialogChromeOnly.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=931768
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 931768</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 931768 **/
+
+ try {
+ openDialog(AppConstants.BROWSER_CHROME_URL);
+ ok(false, "Calling openDialog from unprivileged script should throw.");
+ } catch (e) {
+ ok(e instanceof ReferenceError,
+ "openDialog shouldn't be available to unprivileged script.");
+ }
+</script>
+</body>
+
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=931768">Mozilla Bug 931768</a>
+<p id="display">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_open_null_features.html b/dom/base/test/test_open_null_features.html
new file mode 100644
index 0000000000..b7f3fb5008
--- /dev/null
+++ b/dom/base/test/test_open_null_features.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1009529
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1009529</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 1009529 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var win1 = open("about:blank", "_blank", null);
+ var win2 = open("about:blank", "_blank", "");
+ for (var k in win1) {
+ var v;
+ try {
+ v = win1[k];
+ } catch (ex) {}
+ if (v instanceof win1.BarProp) {
+ is(v.visible, win2[k] && win2[k].visible, "Both windows should have the same value for " + k);
+ }
+ }
+
+ var closeCount = 0;
+ var closeInc = function(e) {
+ this.removeEventListener("unload", closeInc, true);
+ closeCount++;
+ if (closeCount == 2) {
+ SimpleTest.finish();
+ }
+ };
+ win1.addEventListener("unload", closeInc, true);
+ win2.addEventListener("unload", closeInc, true);
+ win1.close();
+ win2.close();
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1009529">Mozilla Bug 1009529</a>
+<p id="display">
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_pasting_svg_image.html b/dom/base/test/test_pasting_svg_image.html
new file mode 100644
index 0000000000..be22f92f3a
--- /dev/null
+++ b/dom/base/test/test_pasting_svg_image.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test pasting &lt;svg&gt;&lt;image href&gt;</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ const kPasteTargetId = "pasteTarget";
+ const kTestContentId = "testContent";
+
+ function selectSVG() {
+ const testContent = document.getElementById(kTestContentId);
+ document.getSelection().selectAllChildren(testContent);
+ }
+
+ async function copyToClipboard() {
+ function validatorFn(aData) {
+ const testContent = document.getElementById(kTestContentId);
+
+ let expectedData = testContent.outerHTML;
+ if (navigator.platform.includes(kPlatformWindows)) {
+ expectedData = kTextHtmlPrefixClipboardDataWindows +
+ expectedData + kTextHtmlSuffixClipboardDataWindows;
+ }
+
+ return SimpleTest.stripLinebreaksAndWhitespaceAfterTags(aData) ==
+ SimpleTest.stripLinebreaksAndWhitespaceAfterTags(expectedData);
+ }
+
+ function setupFn() {
+ synthesizeKey("c", { accelKey: true } /* aEvent */);
+ }
+
+ const flavor = "text/html";
+
+ await SimpleTest.promiseClipboardChange(validatorFn, setupFn, flavor);
+ }
+
+ async function pasteTo(aTargetElement) {
+ document.getSelection().selectAllChildren(aTargetElement);
+
+ const promiseInputEvent = new Promise(resolve => {
+ document.addEventListener("input", resolve,
+ { once: true } /* options */);
+ synthesizeKey("v", { accelKey: true } /* aEvent */);
+ });
+
+ await promiseInputEvent;
+ }
+
+ async function runTest() {
+ selectSVG();
+ await copyToClipboard();
+
+ // Get the test-content before pasting, because pasting will duplicate
+ // ids.
+ const expectedPastedInnerHTML =
+ SimpleTest.stripLinebreaksAndWhitespaceAfterTags(
+ document.getElementById(kTestContentId).outerHTML);
+
+ const pasteTargetElement = document.getElementById(kPasteTargetId);
+ await pasteTo(pasteTargetElement);
+
+ const pastedInnerHTMLWithoutLinebreaksAndWhitespaceAfterTags =
+ SimpleTest.stripLinebreaksAndWhitespaceAfterTags(
+ pasteTargetElement.innerHTML);
+
+ is(pastedInnerHTMLWithoutLinebreaksAndWhitespaceAfterTags,
+ expectedPastedInnerHTML,
+ "Pasted HTML is as expected.");
+
+ SimpleTest.finish()
+ }
+
+ function onLoad() {
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.waitForFocus(runTest);
+ };
+ </script>
+</head>
+<body onload="onLoad()">
+ <h6>
+ Test for <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1669050">bug 1669050</a>
+ </h6>
+<div id="testContent">
+ foo
+ <svg>
+ <image
+ href="http://mochi.test:8888/tests/dom/base/test/name_of_some_image_file.png"
+ height="200" width="200">
+ </image>
+ </svg>
+ bar
+</div>
+<div contenteditable id="pasteTarget"/>
+</body>
+</html>
diff --git a/dom/base/test/test_pdf_print.html b/dom/base/test/test_pdf_print.html
new file mode 100644
index 0000000000..6e73ae2a09
--- /dev/null
+++ b/dom/base/test/test_pdf_print.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title><!-- TODO: insert title here --></title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ const blob = new Blob(["x"], { type: "application/pdf" });
+ const blobURL = URL.createObjectURL(blob);
+ const blobFrame = document.createElement("iframe");
+ blobFrame.src = blobURL;
+ document.getElementById("content").appendChild(blobFrame);
+
+ const dataURL = "data:application/pdf,";
+ const dataFrame = document.createElement("iframe");
+ dataFrame.src = dataURL;
+ document.getElementById("content").appendChild(dataFrame);
+
+ addLoadEvent(function() {
+ // blob:// URLs inherit their origin, so the window inside blobFrame
+ // should be same-orgin with us except for the PDF viewer messing with
+ // origins.
+ const printFunc = blobFrame.contentWindow.print;
+ is(typeof printFunc, "function", "Should have a 'print' function");
+ ok(Object.getOwnPropertyNames(blobFrame.contentWindow).includes("print"),
+ "Should see 'print' property in property names");
+
+ try {
+ // data: URLs get nonce origins, so the window inside dataFrame is not
+ // same-origin with us in any way.
+ dataFrame.contentWindow.print;
+ ok(false, "Should throw on cross-origin .print access");
+ } catch (e) {
+ ok(/Permission denied/.test(e.message), "Should have a security error");
+ }
+ ok(!Object.getOwnPropertyNames(dataFrame.contentWindow).includes("print"),
+ "Should not see 'print' property in property names");
+
+ try {
+ printFunc.call(dataFrame.contentWindow);
+ ok(false, "Should throw on cross-origin call");
+ } catch (e) {
+ ok(/Permission to call/.test(e.message),
+ "Should have a security error for call");
+ }
+
+ // It'd be nice to test that calling the function works right, but if it
+ // does it'll put up the print dialog, which is not helpful in an
+ // automated test.
+ SimpleTest.finish();
+ });
+ </script>
+</div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_plugin_freezing.html b/dom/base/test/test_plugin_freezing.html
new file mode 100644
index 0000000000..99174aa9bb
--- /dev/null
+++ b/dom/base/test/test_plugin_freezing.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for plugin freezing and thawing</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>
+<div id="content" style="display: none">
+</div>
+<embed id='e1' type='application/x-test'></embed>
+<script>
+var e1 = document.getElementById('e1');
+var w;
+
+var testIndex = 0;
+var tests;
+
+window.addEventListener("unload", function() {
+ e1.stopWatchingInstanceCount();
+});
+
+function nextTest() {
+ if (testIndex == tests.length) {
+ if (w) {
+ w.close();
+ }
+ SimpleTest.waitForFocus(function() {
+ SimpleTest.finish();
+ });
+ return;
+ }
+
+ var test = tests[testIndex];
+ ++testIndex;
+ test();
+}
+
+function waitForInstanceCount(n) {
+ if (e1.getInstanceCount() == n) {
+ ok(true, "reached instance count " + n);
+ nextTest();
+ return;
+ }
+ setTimeout(function() { waitForInstanceCount(n); }, 0);
+}
+
+tests = [
+ function() { waitForInstanceCount(1); },
+ function() { w.location.href = "about:blank";
+ waitForInstanceCount(0); },
+];
+
+try {
+ e1.startWatchingInstanceCount();
+ var w = window.open("data:text/html,<embed id='e2' type='application/x-test'></embed>");
+ SimpleTest.waitForFocus(nextTest, w);
+ SimpleTest.waitForExplicitFinish();
+} catch (err) {
+ todo(false, "Instances already being watched?");
+}
+
+</script>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_postMessage_originAttributes.html b/dom/base/test/test_postMessage_originAttributes.html
new file mode 100644
index 0000000000..7dab671ec1
--- /dev/null
+++ b/dom/base/test/test_postMessage_originAttributes.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test window.postMessages from system principal to window with non-default originAttributes</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<iframe id="target-iframe"></iframe>
+<script type="application/javascript">
+
+add_task(async function() {
+ let iframe = document.querySelector("#target-iframe");
+
+ let win = SpecialPowers.wrap(iframe).contentWindow;
+ let docShell = win.docShell;
+
+ // Add private browsing ID to docShell origin and load document.
+ docShell.setOriginAttributes({privateBrowsingId: 1});
+
+ await new Promise(resolve => {
+ iframe.addEventListener("load", resolve, true);
+
+ iframe.src = SimpleTest.getTestFileURL("file_receiveMessage.html");
+ });
+
+ // Set up console monitor to wait for warning.
+ const expectedMessage = (
+ 'Attempting to post a message to window with url ' +
+ '"http://mochi.test:8888/tests/dom/base/test/file_receiveMessage.html" ' +
+ 'and origin "http://mochi.test:8888^privateBrowsingId=1" from a system ' +
+ 'principal scope with mismatched origin "[System Principal]".');
+
+ let consolePromise = new Promise(resolve => {
+ SimpleTest.monitorConsole(resolve, [e => e.message == expectedMessage]);
+ });
+
+ // Post to the content window via SpecialPowers' system principal scope.
+ win.postMessage("Hello. o/", "http://mochi.test:8888");
+ await new Promise(resolve => setTimeout(resolve, 0));
+
+ SimpleTest.endMonitorConsole();
+ await consolePromise;
+
+ // Check that the window received and handled the message.
+ is(win.document.body.textContent, "|Hello. o/",
+ "Content window received the expected message");
+});
+</script>
+</body>
+</html>
+
diff --git a/dom/base/test/test_postMessage_solidus.html b/dom/base/test/test_postMessage_solidus.html
new file mode 100644
index 0000000000..42124e35ef
--- /dev/null
+++ b/dom/base/test/test_postMessage_solidus.html
@@ -0,0 +1,93 @@
+
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=949488
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 949488 - basic support</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=949488">Mozilla Bug 949488</a>
+ <div id="content"></div>
+ <script type="application/javascript">
+
+ function selfMessage() {
+ addEventListener('message', receiveMessage);
+ function receiveMessage(evt) {
+ is(evt.data, 1, "Message received");
+ removeEventListener('message', receiveMessage);
+ runTest();
+ }
+
+ postMessage(1, '/');
+ }
+
+ function frameOk() {
+ var ifr = document.createElement("iframe");
+ ifr.addEventListener("load", iframeLoaded);
+ ifr.setAttribute('src', "iframe_postMessage_solidus.html");
+
+ var div = document.getElementById("content");
+ div.appendChild(ifr);
+
+ function iframeLoaded() {
+ addEventListener('message', receiveMessage);
+ function receiveMessage(evt) {
+ is(evt.data, 2, "Message received");
+ removeEventListener('message', receiveMessage);
+ runTest();
+ }
+
+ ifr.contentWindow.postMessage(2, '/');
+ }
+ }
+
+ function frameWrong() {
+ var ifr = document.createElement("iframe");
+ ifr.addEventListener("load", iframeLoaded);
+ ifr.setAttribute('src', "http://www.example.com/tests/dom/base/test/iframe_postMessage_solidus.html");
+
+ var div = document.getElementById("content");
+ div.appendChild(ifr);
+
+ function iframeLoaded() {
+ addEventListener('message', receiveMessage);
+ function receiveMessage(evt) {
+ is(evt.data, 3, "Message received");
+ removeEventListener('message', receiveMessage);
+ runTest();
+ }
+
+ ifr.contentWindow.postMessage(4, '/');
+ SimpleTest.executeSoon(function() {
+ ifr.contentWindow.postMessage(3, '*');
+ });
+ }
+ }
+
+ var tests = [
+ selfMessage,
+ frameOk,
+ frameWrong
+ ];
+
+ function runTest() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ runTest();
+
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_postMessages_broadcastChannel.html b/dom/base/test/test_postMessages_broadcastChannel.html
new file mode 100644
index 0000000000..a3864d0710
--- /dev/null
+++ b/dom/base/test/test_postMessages_broadcastChannel.html
@@ -0,0 +1,167 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for postMessages cloning/transferring objects</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script src="common_postMessages.js"></script>
+</head>
+
+<body>
+<input id="fileList" type="file"></input>
+<script type="application/javascript">
+
+// PostMessage for BroadcastChannel
+tests.push(function test_broadcastChannel() {
+ info("Testing broadcastChannel");
+
+ var bc1 = new BroadcastChannel('postMessagesTest');
+ var bc2 = new BroadcastChannel('postMessagesTest');
+
+ var resolve;
+
+ function resolvePromise(data) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp(data);
+ }
+
+ bc2.onmessage = function(e) {
+ resolvePromise({ data: e.data, ports: [], error: false });
+ }
+
+ bc2.onmessageerror = function(e) {
+ resolvePromise({ error: true });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: false,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ if (ports.length) {
+ rr();
+ return;
+ }
+
+ resolve = r;
+ bc1.postMessage(what);
+ });
+ },
+
+ finished() {
+ bc1.close();
+ bc2.close();
+ next();
+ }
+ });
+});
+
+// PostMessage for BroadcastChannel in workers
+tests.push(function test_broadcastChannel_inWorkers() {
+ info("Testing broadcastChannel in Workers");
+
+ var bc = new BroadcastChannel('postMessagesTest_inWorkers');
+ var resolve;
+
+ var w = new Worker('worker_postMessages.js');
+ w.postMessage('broadcastChannel');
+ w.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.onmessage = function(e1) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e1.data, ports: e1.ports, error: e1.data === "error" });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: false,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ if (ports.length) {
+ rr();
+ return;
+ }
+
+ resolve = r;
+ bc.postMessage(what);
+ });
+ },
+
+ finished() {
+ bc.close();
+ w.terminate();
+ next();
+ }
+ });
+ }
+});
+
+// PostMessage for BroadcastChannel in SharedWorkers
+tests.push(function test_broadcastChannel_inSharedWorkers() {
+ info("Testing broadcastChannel in SharedWorkers");
+
+ var bc = new BroadcastChannel('postMessagesTest_inWorkers');
+ var resolve;
+
+ var w = new SharedWorker('worker_postMessages.js');
+ w.port.postMessage('broadcastChannel');
+ w.port.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.port.onmessage = function(e1) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e1.data, ports: e1.ports, error: e1.data === "error" });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: false,
+ transferableObjects: false,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ if (ports.length) {
+ rr();
+ return;
+ }
+
+ resolve = r;
+ bc.postMessage(what);
+ });
+ },
+
+ finished() {
+ bc.close();
+ w.port.postMessage("terminate");
+ next();
+ }
+ });
+ }
+});
+
+SimpleTest.waitForExplicitFinish();
+next();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_postMessages_messagePort.html b/dom/base/test/test_postMessages_messagePort.html
new file mode 100644
index 0000000000..5797c23c5c
--- /dev/null
+++ b/dom/base/test/test_postMessages_messagePort.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for postMessages cloning/transferring objects</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script src="common_postMessages.js"></script>
+</head>
+
+<body>
+<input id="fileList" type="file"></input>
+<script type="application/javascript">
+
+// PostMessage for MessagePort
+tests.push(function test_messagePort() {
+ info("Testing messagePort");
+
+ var mc = new MessageChannel();
+ var resolve;
+
+ function resolvePromise(data) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp(data);
+ }
+
+ mc.port2.onmessage = function(e) {
+ resolvePromise({ data: e.data, ports: e.ports, error: false });
+ }
+
+ mc.port2.onmessageerror = function(e) {
+ resolvePromise({ error: true });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: true,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ mc.port1.postMessage(what, ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished() {
+ next();
+ }
+ });
+});
+
+// PostMessage for MessagePort in Workers
+tests.push(function test_messagePort_inWorkers() {
+ info("Testing messagePort in workers");
+
+ var mc = new MessageChannel();
+ var resolve;
+
+ var w = new Worker('worker_postMessages.js');
+ w.postMessage('messagePort', [ mc.port2 ]);
+ w.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.onmessage = function(e1) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e1.data, ports: e1.ports, error: e1.data === "error" });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: true,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ mc.port1.postMessage(what, ports);
+ } catch(ex) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished() {
+ w.terminate();
+ next();
+ }
+ });
+ }
+});
+
+SimpleTest.waitForExplicitFinish();
+next();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_postMessages_window.html b/dom/base/test/test_postMessages_window.html
new file mode 100644
index 0000000000..12b757867b
--- /dev/null
+++ b/dom/base/test/test_postMessages_window.html
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for postMessages cloning/transferring objects</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script src="common_postMessages.js"></script>
+</head>
+
+<body>
+<input id="fileList" type="file"></input>
+<script type="application/javascript">
+
+// PostMessage to the same window.
+tests.push(function test_windowToWindow() {
+ info("Testing window to window");
+ var resolve;
+
+ function resolvePromise(data) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp(data);
+ }
+
+ onmessage = function(e) {
+ resolvePromise({ data: e.data, ports: e.ports, error: false });
+ }
+
+ onmessageerror = function(e) {
+ resolvePromise({ error: true });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: true,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+
+ try {
+ postMessage(what, '*', ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished() {
+ onmessage = null;
+ onmessageerror = null;
+ next();
+ }
+ });
+});
+
+// iframe helper class
+function test_windowToIframeURL(url, clonableObjectsSameProcess) {
+ var resolve;
+
+ onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: e.ports, error: e.data === "error" });
+ }
+
+ var ifr = document.createElement('iframe');
+ ifr.src = url;
+ ifr.onload = function() {
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess,
+ transferableObjects: true,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ ifr.contentWindow.postMessage(what, '*', ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished() {
+ document.body.removeChild(ifr);
+ onmessage = null;
+ next();
+ }
+ });
+ }
+ document.body.appendChild(ifr);
+}
+
+// PostMessage to iframe
+tests.push(function test_windowToIframe() {
+ info("Testing window to iframe");
+ test_windowToIframeURL('iframe_postMessages.html', true);
+});
+
+// PostMessage to cross-origin iframe
+tests.push(function test_windowToCrossOriginIframe() {
+ info("Testing window to cross-origin iframe");
+ test_windowToIframeURL('http://example.com/tests/dom/base/test/iframe_postMessages.html', false);
+});
+
+SimpleTest.waitForExplicitFinish();
+next();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_postMessages_workers.html b/dom/base/test/test_postMessages_workers.html
new file mode 100644
index 0000000000..994c0201e6
--- /dev/null
+++ b/dom/base/test/test_postMessages_workers.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for postMessages cloning/transferring objects</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script src="common_postMessages.js"></script>
+</head>
+
+<body>
+<input id="fileList" type="file"></input>
+<script type="application/javascript">
+
+// PostMessage for Workers
+tests.push(function test_workers() {
+ info("Testing Workers");
+
+ var resolve;
+
+ var w = new Worker('worker_postMessages.js');
+ w.postMessage('workers');
+ w.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.onmessage = function(e1) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e1.data, ports: e1.ports, error: e1.data === "error" });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: true,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ w.postMessage(what, ports);
+ } catch(ex) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished() {
+ w.terminate();
+ next();
+ }
+ });
+ }
+});
+
+// PostMessage for SharedWorkers
+tests.push(function test_sharedWorkers() {
+ info("Testing SharedWorkers");
+
+ var resolve;
+
+ var w = new SharedWorker('worker_postMessages.js');
+ w.port.postMessage('sharedworkers');
+ w.port.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.port.onmessage = function(e1) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e1.data, ports: e1.ports, error: e1.data === "error" });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: false,
+ transferableObjects: true,
+ send(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ w.port.postMessage(what, ports);
+ } catch(ex) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished() {
+ w.port.postMessage("terminate");
+ next();
+ }
+ });
+ }
+});
+
+SimpleTest.waitForExplicitFinish();
+next();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_processing_instruction_update_stylesheet.xhtml b/dom/base/test/test_processing_instruction_update_stylesheet.xhtml
new file mode 100644
index 0000000000..85aeea25a2
--- /dev/null
+++ b/dom/base/test/test_processing_instruction_update_stylesheet.xhtml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="data:text/css;charset=UTF-8,p{color:red}" type="text/css"?>
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=888864
+-->
+<head>
+ <title>Test for Bug 888864</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 888864 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function changeColorAndRun(callback) {
+ var piNode = document.firstChild;
+ piNode.data = 'href="data:text/css;charset=UTF-8,p{color:green}" type="text/css"';
+ piNode.addEventListener("load", callback);
+ }
+
+ function runTest() {
+ var previousColor = window.getComputedStyle(document.getElementById("display")).
+ getPropertyValue("color");
+ changeColorAndRun(function() {
+ var afterChange = window.getComputedStyle(document.getElementById("display")).
+ getPropertyValue("color");
+ isnot(previousColor, afterChange,
+ "Color of the p element should change.");
+ SimpleTest.finish();
+ });
+ }
+ ]]>
+</script>
+</head>
+<body onload="runTest();">
+<p id="display">This changes color</p>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=888864">Mozilla Bug 888864</a>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_progress_events_for_gzip_data.html b/dom/base/test/test_progress_events_for_gzip_data.html
new file mode 100644
index 0000000000..2d73511457
--- /dev/null
+++ b/dom/base/test/test_progress_events_for_gzip_data.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test progess events in case of gzipped data.</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="onLoadData()">
+<script class="testbody" type="text/javascript">"use strict";
+SimpleTest.waitForExplicitFinish();
+
+var url = "send_gzip_content.sjs";
+var loaded = 0;
+var total = 0;
+
+function onProgress(e) {
+ if(e.lengthComputable) {
+ loaded = e.loaded;
+ total = e.total;
+ if (loaded > total) {
+ ok(false, "We have loaded more bytes (" + loaded +
+ ") than the total amount of bytes (" + total +
+ ") available!!!");
+ }
+ }
+}
+
+function onLoadData() {
+ var xhr = new XMLHttpRequest();
+ xhr.addEventListener('progress', onProgress);
+ xhr.open('GET', url, true);
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ is(loaded, total, "loaded should be equal to total");
+ isnot(loaded, 0, "loaded should be bigger than 0");
+ SimpleTest.finish();
+ }
+ }
+ xhr.send(null);
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_pushState_structuredclone.html b/dom/base/test/test_pushState_structuredclone.html
new file mode 100644
index 0000000000..7051b15a2a
--- /dev/null
+++ b/dom/base/test/test_pushState_structuredclone.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <title>history.pushState with serializable objects in state</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<script>
+ add_task(async function test() {
+ let state = {
+ b: new Blob(['1234567890']),
+ // CryptoKey
+ k: await crypto.subtle.generateKey({ name: "HMAC", length: 256, hash: {name: "SHA-256"} }, true, ["sign", "verify"]),
+ mr: new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6]),
+ m: new DOMMatrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
+ pr: new DOMPointReadOnly(1, 2, 3, 4),
+ p: new DOMPoint(4, 3, 2, 1),
+ q: new DOMQuad(new DOMRectReadOnly(1, 2, 3, 4)),
+ rr: new DOMRectReadOnly(1, 2, 3, 4),
+ r: new DOMRect(1, 2, 3, 4),
+ f: new File(['9876543210'], ''),
+ i: new ImageData(4, 4),
+ // RTCCertificate
+ c: await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256' }),
+ };
+
+ history.pushState(state, "", "?withState");
+ ok(history.state instanceof Object,
+ "pushState with an object should set history.state.");
+ SimpleTest.isDeeply(history.state, state,
+ "Check that history.state retains all serializable fields.");
+
+ history.pushState(undefined, "", "?withoutState");
+ let promisePoppedState = new Promise(resolve => {
+ window.addEventListener('popstate', event => {
+ resolve(event.state);
+ }, { once: true });
+ });
+ history.back();
+ let poppedState = await promisePoppedState;
+ ok(poppedState instanceof Object,
+ "Going back from pushState with an object should return an object in the popstate event.");
+ SimpleTest.isDeeply(poppedState, state,
+ "Check that going back from pushState retains all serializable fields.");
+ });
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_range_bounds.html b/dom/base/test/test_range_bounds.html
new file mode 100644
index 0000000000..657d315198
--- /dev/null
+++ b/dom/base/test/test_range_bounds.html
@@ -0,0 +1,305 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=421640
+-->
+<head>
+ <title>Test for Bug 396392</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <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=396392">Mozilla Bug Range getClientRects and getBoundingClientRect</a>
+<div id="content" style="font-family:monospace;font-size:12px;width:100px">
+<p>000000<span>0</span></p><div>00000<span>0</span></div><p>0000<span>0000</span>0000</p><div><span>000000000000 00000000000000 000000</span></div><div>000000000000 00000000000003 100305</div>
+</div>
+<div id="mixeddir" style="font-family:monospace;font-size:12px;width:100px"><span>english <bdo id="bdo" dir="rtl">rtl-overide english</bdo> word</span></div>
+<div id="mixeddir2" style="font-family:monospace;font-size:12px"><span>english <bdo id="bdo2" dir="rtl">rtl-override english</bdo> word</span></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var isLTR = true;
+var isTransformed = false;
+
+function annotateName(name) {
+ return (isLTR ? 'isLTR ' : 'isRTL ') +
+ (isTransformed ? 'transformed ' : '') + name;
+}
+
+function isEmptyRect(rect, name) {
+ name = annotateName(name);
+ is(rect.left, 0, name+'empty rect should have left = 0');
+ is(rect.right, 0, name+'empty rect should have right = 0');
+ is(rect.top, 0, name+'empty rect should have top = 0');
+ is(rect.bottom, 0, name+'empty rect should have bottom = 0');
+ is(rect.width, 0, name+'empty rect should have width = 0');
+ is(rect.height, 0, name+'empty rect should have height = 0');
+}
+
+function isEmptyRectList(rectlist, name) {
+ name = annotateName(name);
+ is(rectlist.length, 0, name + 'empty rectlist should have zero rects');
+}
+
+// round coordinates to the nearest 1/256 of a pixel
+function roundCoord(x) {
+ return Math.round(x * 256) / 256;
+}
+
+function _getRect(r) {
+ if (r.length) //array
+ return "{left:"+roundCoord(r[0])+",right:"+roundCoord(r[1])+
+ ",top:" +roundCoord(r[2])+",bottom:"+roundCoord(r[3])+
+ ",width:"+roundCoord(r[4])+",height:"+roundCoord(r[5])+"}";
+ else
+ return "{left:"+roundCoord(r.left)+",right:"+roundCoord(r.right)+
+ ",top:"+roundCoord(r.top)+",bottom:"+roundCoord(r.bottom)+
+ ",width:"+roundCoord(r.width)+",height:"+roundCoord(r.height)+"}";
+}
+
+function runATest(obj) {
+ var range = document.createRange();
+ try {
+ range.setStart(obj.range[0],obj.range[1]);
+ if (obj.range.length>2) {
+ range.setEnd(obj.range[2]||obj.range[0], obj.range[3]);
+ }
+ //test getBoundingClientRect()
+ var rect = range.getBoundingClientRect();
+ var testname = 'range.getBoundingClientRect for ' + obj.name;
+ if (obj.rect) {
+ is(_getRect(rect),_getRect(obj.rect), annotateName(testname));
+ } else {
+ isEmptyRect(rect,testname+": ");
+ }
+ //test getClientRects()
+ var rectlist = range.getClientRects();
+ testname = 'range.getClientRects for ' + obj.name;
+ if (!obj.rectList) {
+ //rectList is not specified, use obj.rect to figure out rectList
+ obj.rectList = obj.rect?[obj.rect]:[];
+ }
+ if (!obj.rectList.length) {
+ isEmptyRectList(rectlist, testname+": ");
+ } else {
+ is(rectlist.length, obj.rectList.length,
+ annotateName(testname+' should return '+obj.rectList.length+' rects.'));
+ if(!obj.rectList.forEach){
+ //convert RectList to a real array
+ obj.rectList=Array.prototype.slice.call(obj.rectList, 0);
+ }
+ obj.rectList.forEach(function(r,i) {
+ is(_getRect(rectlist[i]),_getRect(r),
+ annotateName(testname+": item at "+i));
+ });
+ }
+ } finally {
+ range.detach();
+ }
+}
+/** Test for Bug 396392 **/
+function doTest(){
+ var root = document.getElementById('content');
+ var firstP = root.firstElementChild, spanInFirstP = firstP.childNodes[1],
+ firstDiv = root.childNodes[2], spanInFirstDiv = firstDiv.childNodes[1],
+ secondP = root.childNodes[3], spanInSecondP = secondP.childNodes[1],
+ secondDiv = root.childNodes[4], spanInSecondDiv = secondDiv.firstChild,
+ thirdDiv = root.childNodes[5];
+ var firstPRect = firstP.getBoundingClientRect(),
+ spanInFirstPRect = spanInFirstP.getBoundingClientRect(),
+ firstDivRect = firstDiv.getBoundingClientRect(),
+ spanInFirstDivRect = spanInFirstDiv.getBoundingClientRect(),
+ secondPRect = secondP.getBoundingClientRect(),
+ secondDivRect = secondDiv.getBoundingClientRect(),
+ spanInSecondPRect = spanInSecondP.getBoundingClientRect(),
+ spanInSecondDivRect = spanInSecondDiv.getBoundingClientRect(),
+ spanInSecondDivRectList = spanInSecondDiv.getClientRects();
+ var widthPerchar = spanInSecondPRect.width / spanInSecondP.firstChild.length;
+ var testcases = [
+ {name:'nodesNotInDocument', range:[document.createTextNode('abc'), 1],
+ rect:null},
+ {name:'collapsedInBlockNode', range:[firstP, 2], rect:null},
+ {name:'collapsedAtBeginningOfTextNode', range:[firstP.firstChild, 0],
+ rect:[spanInFirstPRect.left - 6 * widthPerchar,
+ spanInFirstPRect.left - 6 * widthPerchar, spanInFirstPRect.top,
+ spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
+ {name:'collapsedWithinTextNode', range:[firstP.firstChild, 1],
+ rect:[spanInFirstPRect.left - 5 * widthPerchar,
+ spanInFirstPRect.left - 5 * widthPerchar,
+ spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
+ {name:'collapsedAtEndOfTextNode', range:[firstP.firstChild, 6],
+ rect:[spanInFirstPRect.left, spanInFirstPRect.left,
+ spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
+ {name:'singleBlockNode', range:[root, 1, root, 2], rect:firstPRect},
+ {name:'twoBlockNodes', range:[root, 1, root, 3],
+ rect:[firstPRect.left, firstPRect.right, firstPRect.top,
+ firstDivRect.bottom, firstPRect.width,
+ firstDivRect.bottom - firstPRect.top],
+ rectList:[firstPRect, firstDivRect]},
+ {name:'endOfTextNodeToEndOfAnotherTextNodeInAnotherBlock',
+ range:[spanInFirstP.firstChild, 1, firstDiv.firstChild, 5],
+ rect:[spanInFirstDivRect.left - 5*widthPerchar, spanInFirstDivRect.left,
+ spanInFirstDivRect.top, spanInFirstDivRect.bottom, 5 * widthPerchar,
+ spanInFirstDivRect.height]},
+ {name:'startOfTextNodeToStartOfAnotherTextNodeInAnotherBlock',
+ range:[spanInFirstP.firstChild, 0, firstDiv.firstChild, 0],
+ rect:[spanInFirstPRect.left, spanInFirstPRect.left + widthPerchar, spanInFirstPRect.top,
+ spanInFirstPRect.bottom, widthPerchar, spanInFirstPRect.height]},
+ {name:'endPortionOfATextNode', range:[firstP.firstChild, 3,
+ firstP.firstChild, 6],
+ rect:[spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.left,
+ spanInFirstPRect.top, spanInFirstPRect.bottom, 3*widthPerchar, spanInFirstPRect.height]},
+ {name:'startPortionOfATextNode', range:[firstP.firstChild, 0,
+ firstP.firstChild, 3],
+ rect:[spanInFirstPRect.left - 6*widthPerchar,
+ spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.top,
+ spanInFirstPRect.bottom, 3 * widthPerchar, spanInFirstPRect.height]},
+ {name:'spanTextNodes', range:[secondP.firstChild, 1, secondP.lastChild, 1],
+ rect:[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.right +
+ widthPerchar, spanInSecondPRect.top, spanInSecondPRect.bottom,
+ spanInSecondPRect.width + 4*widthPerchar, spanInSecondPRect.height],
+ rectList:[[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.left,
+ spanInSecondPRect.top, spanInSecondPRect.bottom, 3 * widthPerchar,
+ spanInSecondPRect.height],
+ spanInSecondPRect,
+ [spanInSecondPRect.right, spanInSecondPRect.right + widthPerchar,
+ spanInSecondPRect.top, spanInSecondPRect.bottom, widthPerchar,
+ spanInSecondPRect.height]]}
+ ];
+ testcases.forEach(runATest);
+
+ // testcases that have different ranges in LTR and RTL
+ var directionDependentTestcases;
+ if (isLTR) {
+ directionDependentTestcases = [
+ {name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30],
+ rect: spanInSecondDivRect,
+ rectList:[[spanInSecondDivRectList[0].left+widthPerchar,
+ spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top,
+ spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar,
+ spanInSecondDivRectList[0].height],
+ spanInSecondDivRectList[1],
+ [spanInSecondDivRectList[2].left,
+ spanInSecondDivRectList[2].right - 4 * widthPerchar, spanInSecondDivRectList[2].top,
+ spanInSecondDivRectList[2].bottom,
+ spanInSecondDivRectList[2].width - 4 * widthPerchar,
+ spanInSecondDivRectList[2].height]]},
+ {name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28],
+ rect: [spanInSecondDivRectList[1].left, spanInSecondDivRectList[1].right,
+ spanInSecondDivRectList[1].top + secondDivRect.height,
+ spanInSecondDivRectList[1].bottom + secondDivRect.height,
+ spanInSecondDivRectList[1].width, spanInSecondDivRectList[1].height]}
+ ];
+ } else {
+ directionDependentTestcases = [
+ {name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30],
+ rect: spanInSecondDivRect,
+ rectList:[[spanInSecondDivRectList[0].left+widthPerchar,
+ spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top,
+ spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar,
+ spanInSecondDivRectList[0].height],
+ spanInSecondDivRectList[1],
+ spanInSecondDivRectList[2],
+ spanInSecondDivRectList[3],
+ [spanInSecondDivRectList[4].left,
+ spanInSecondDivRectList[4].right - 4 * widthPerchar,
+ spanInSecondDivRectList[4].top,
+ spanInSecondDivRectList[4].bottom,
+ spanInSecondDivRectList[4].width - 4 * widthPerchar,
+ spanInSecondDivRectList[4].height]]},
+ {name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28],
+ rect: [spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right,
+ spanInSecondDivRectList[2].top + secondDivRect.height,
+ spanInSecondDivRectList[2].bottom + secondDivRect.height,
+ spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height],
+ rectList:[[spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right,
+ spanInSecondDivRectList[2].top + secondDivRect.height,
+ spanInSecondDivRectList[2].bottom + secondDivRect.height,
+ spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height],
+ [spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].left,
+ spanInSecondDivRectList[2].top + secondDivRect.height,
+ spanInSecondDivRectList[2].bottom + secondDivRect.height,
+ 0, spanInSecondDivRectList[2].height]]}
+ ];
+ }
+ directionDependentTestcases.forEach(runATest);
+}
+function testMixedDir(){
+ var root = document.getElementById('mixeddir');
+ var firstSpan = root.firstElementChild, firstSpanRect=firstSpan.getBoundingClientRect(),
+ firstSpanRectList = firstSpan.getClientRects();
+ runATest({name:'mixeddir',range:[firstSpan.firstChild,0,firstSpan.lastChild,firstSpan.lastChild.length],
+ rect: firstSpanRect, rectList:firstSpanRectList});
+
+ root = document.getElementById('mixeddir2');
+ firstSpan = root.firstElementChild;
+ firstSpanRect = firstSpan.getBoundingClientRect();
+ bdo = document.getElementById('bdo2');
+ bdoRect=bdo.getBoundingClientRect();
+ var widthPerChar = bdoRect.width / bdo.firstChild.length;
+ runATest({name:'mixeddirPartial', range:[firstSpan.firstChild, 3,
+ bdo.firstChild, 7],
+ rect: [firstSpanRect.left + 3*widthPerChar, bdoRect.right,
+ bdoRect.top, bdoRect.bottom,
+ (firstSpan.firstChild.length + bdo.firstChild.length - 3) *
+ widthPerChar,
+ bdoRect.height],
+ rectList:[[firstSpanRect.left + 3*widthPerChar,
+ bdoRect.left,
+ firstSpanRect.top, firstSpanRect.bottom,
+ (firstSpan.firstChild.length - 3) * widthPerChar,
+ firstSpanRect.height],
+ [bdoRect.right - 7 * widthPerChar, bdoRect.right,
+ bdoRect.top, bdoRect.bottom,
+ 7*widthPerChar, bdoRect.height]]});
+}
+
+function testShadowDOM() {
+ var ifr = document.createElement("iframe");
+ document.body.appendChild(ifr);
+ var doc = ifr.contentDocument;
+ var d = doc.createElement("div");
+ var sr = d.attachShadow({mode: "open"});
+ sr.innerHTML = "<div>inside shadow DOM</div>";
+ doc.body.appendChild(d);
+ var r = new ifr.contentWindow.Range();
+ r.selectNode(sr.firstChild);
+ var rect = r.getBoundingClientRect();
+ isnot(rect.width, 0, "Div element inside shadow shouldn't have zero size.");
+ isnot(rect.height, 0, "Div element inside shadow shouldn't have zero size.");
+}
+
+function test(){
+ //test ltr
+ doTest();
+
+ //test rtl
+ isLTR = false;
+ var root = document.getElementById('content');
+ root.dir = 'rtl';
+ doTest();
+ isLTR = true;
+ root.dir = 'ltr';
+
+ testMixedDir();
+
+ //test transforms
+ isTransformed = true;
+ root.style.transform = "translate(30px,50px)";
+ doTest();
+
+ testShadowDOM();
+ SimpleTest.finish();
+}
+
+window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+ setTimeout(test, 0);
+};
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_reentrant_flush.html b/dom/base/test/test_reentrant_flush.html
new file mode 100644
index 0000000000..9b606aebc9
--- /dev/null
+++ b/dom/base/test/test_reentrant_flush.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=709256
+-->
+<head>
+ <title>Test for Bug 709256</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=709256">Mozilla Bug 709256</a>
+<p id="display">
+<iframe id="test"
+ style="width: 100px" srcdoc="<body style='width: 100%'>">
+</iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 709256 **/
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+ var ifr = $("test");
+ var bod = ifr.contentDocument.body;
+
+ is(bod.getBoundingClientRect().width, 100,
+ "Width of body should be 100px to start with");
+
+ var resizeHandlerRan = false;
+
+ function handleResize() {
+ resizeHandlerRan = true;
+ is(bod.getBoundingClientRect().width, 50,
+ "Width of body should now be 50px");
+ }
+
+ var win = ifr.contentWindow;
+
+ win.addEventListener("resize", handleResize);
+ SpecialPowers.setFullZoom(win, 2);
+
+ is(resizeHandlerRan, false,
+ "Resize handler should not have run yet for this test to be valid");
+
+ // Now flush out layout on the subdocument, to trigger the resize handler
+ is(bod.getBoundingClientRect().width, 50, "Width of body should still be 50px");
+ window.requestAnimationFrame(function() {
+ is(resizeHandlerRan, true, "Resize handler should have run");
+ win.removeEventListener("resize", handleResize);
+ SimpleTest.finish();
+ });
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_root_iframe.html b/dom/base/test/test_root_iframe.html
new file mode 100644
index 0000000000..2e19f19efc
--- /dev/null
+++ b/dom/base/test/test_root_iframe.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=511084
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 511084</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=511084">Mozilla Bug 511084</a>
+<p id="display"><iframe></iframe></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+ <script type="application/javascript">
+ /** Test for Bug 511084 **/
+ var doc = frames[0].document;
+ doc.replaceChild(doc.createElement("iframe"), doc.documentElement);
+ ok(frames[0][0] instanceof frames[0][0].Window,
+ "Should have a subframe window for a root iframe");
+ </script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_sandbox_and_document_uri.html b/dom/base/test/test_sandbox_and_document_uri.html
new file mode 100644
index 0000000000..27b9c87f52
--- /dev/null
+++ b/dom/base/test/test_sandbox_and_document_uri.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test sandbox inheritance and document uri handling</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ add_task(async function() {
+ await new Promise((resolve) => {
+ window.onmessage = (event) => {
+ is(event.data, "done");
+ resolve();
+ }
+ });
+ });
+ </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<iframe sandbox="allow-popups allow-scripts" srcdoc=
+ "<script>
+ window.onmessage = function(event) { parent.postMessage(event.data, '*'); }
+ /* Open a cross-origin page */
+ window.onload = function() { window.open('http://example.org/tests/dom/base/test/file_sandbox_and_document_uri.html'); }
+ </script>"
+ ></iframe>
+</body>
+</html>
diff --git a/dom/base/test/test_sandboxed_blob_uri.html b/dom/base/test/test_sandboxed_blob_uri.html
new file mode 100644
index 0000000000..09568d7641
--- /dev/null
+++ b/dom/base/test/test_sandboxed_blob_uri.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Principal in MessageManager</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+</head>
+<body>
+
+ <script type="application/javascript">
+ "use strict";
+
+ var sb = new Cu.Sandbox('https://example.com', { wantGlobalProperties: [ 'Blob', 'URL' ] });
+ Cu.evalInSandbox('var u = URL.createObjectURL(new Blob(["text"], { type: "text/plain" }));', sb);
+ Cu.nukeSandbox(sb);
+ Cu.forceCC();
+
+ ok(true, "are we leaking blobs?");
+
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_sanitize_xhr.html b/dom/base/test/test_sanitize_xhr.html
new file mode 100644
index 0000000000..3cc0845916
--- /dev/null
+++ b/dom/base/test/test_sanitize_xhr.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1673164
+-->
+<html>
+<head>
+ <title>Test for sanitizing with XHR-loaded owner doc</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet"
+ type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var url = "http://mochi.test:8888/chrome/dom/base/test/file_empty.html"
+var req = new XMLHttpRequest();
+req.open("GET", url, false);
+req.overrideMimeType("text/xml");
+req.send(null);
+var doc = req.responseXML;
+var pu = Cc["@mozilla.org/parserutils;1"].createInstance(Ci.nsIParserUtils);
+var flags = pu.SanitizerDropForms | pu.SanitizerDropMedia;
+var uri = SpecialPowers.Services.io.newURI(url);
+var context = doc.createElement("div");
+var fragment = pu.parseFragment("<form><img onerror=alert(1)><p></p></form>", flags, false, uri, context);
+
+is(fragment.firstChild.localName, "p", "Should have only p.");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_screen_orientation.html b/dom/base/test/test_screen_orientation.html
new file mode 100644
index 0000000000..de0dca8b8b
--- /dev/null
+++ b/dom/base/test/test_screen_orientation.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=760735
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Screen Orientation API</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=760735">Screen Orientation API</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Tests for Screen Orientation API **/
+
+// Screen Orientation API testing is problematic in that not every platform
+// supports orientation-locking, and locking requires running in full-screen.
+// So for now, only negative/sanity testing is done here, as that works globally.
+
+function unexpectedEvent(event) {
+ ok(false, "No unexpected orientation change events received");
+}
+
+window.screen.addEventListener("mozorientationchange", unexpectedEvent);
+try {
+ const allowedOrientations = ["portrait-primary", "portrait-secondary",
+ "landscape-primary", "landscape-secondary"];
+
+ var initialOrientation = window.screen.mozOrientation;
+
+ // Sanity tests
+ isnot(allowedOrientations.indexOf(initialOrientation), -1,
+ "mozOrientation is valid (value=" + initialOrientation + ")");
+
+ // Negative tests
+ ok(!window.screen.mozLockOrientation("Foobar-Bazbam"), "Cannot lock to an invalid string");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(""), "Cannot lock to an empty string");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(["Foobar", "Bazbam"]), "Cannot lock to an invalid string");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(["foo"]), "Cannot lock to an invalid string");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation([""]), "Cannot lock to an empty string");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(42), "Cannot lock to a number");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(undefined), "Cannot lock to undefined");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(null), "Cannot lock to null");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation({}), "Cannot lock to a non-Array object");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(["Foobar", 42]), "Cannot lock to a number");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(["Foobar", null]), "Cannot lock to null");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+
+ ok(!window.screen.mozLockOrientation(["Foobar", undefined]), "Cannot lock to undefined");
+ is(window.screen.mozOrientation, initialOrientation, "Orientation is unchanged");
+} catch (e) {
+ ok(false, "Got unexpected exception: " + e);
+} finally {
+ window.screen.removeEventListener("mozorientationchange", unexpectedEvent);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_script_loader_crossorigin_data_url.html b/dom/base/test/test_script_loader_crossorigin_data_url.html
new file mode 100644
index 0000000000..cfbb90c8df
--- /dev/null
+++ b/dom/base/test/test_script_loader_crossorigin_data_url.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for handling of 'crossorigin' attribute on script with data: URL</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ // We're going to mess with window.onerror.
+ setup({ allow_uncaught_exception: true });
+</script>
+<!-- First check that data: scripts with @crossorigin run at all -->
+<script>
+ var ran = false;
+</script>
+<script crossorigin src="data:application/javascript,ran = true"></script>
+<script>
+test(function() {
+ assert_true(ran);
+}, "script@crossorigin with data: src should have run");
+</script>
+<!-- Then check that their syntax errors are not sanitized -->
+<script>
+var errorFired = false;
+ran = false;
+window.onerror = function(message, uri, line) {
+ errorFired = true;
+ test(function() {
+ assert_equals(line, 3);
+ }, "Should have a useful line number for exception in script@crossorigin with data: src");
+}
+</script>
+<script crossorigin src="data:application/javascript,var%20a;%0aran=true%0anoSuchFunctionHere()"></script>
+<script>
+ test(function() {
+ assert_true(ran, "Script with error should have run");
+ assert_true(errorFired, "Script with error should have fired onerror");
+ }, "Should run and correctly fire onerror");
+</script>
diff --git a/dom/base/test/test_script_loader_js_cache.html b/dom/base/test/test_script_loader_js_cache.html
new file mode 100644
index 0000000000..de168ad109
--- /dev/null
+++ b/dom/base/test/test_script_loader_js_cache.html
@@ -0,0 +1,264 @@
+<!DOCTYPE html>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=900784 -->
+<!-- The JS bytecode cache is not supposed to be observable. To make it
+ observable, the ScriptLoader is instrumented to trigger events on the
+ script tag. These events are followed to reconstruct the code path taken by
+ the script loader and associate a simple name which is checked in these
+ test cases.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for saving and loading bytecode in/from the necko cache</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script type="application/javascript">
+ // This is the state machine of the trace events produced by the
+ // ScriptLoader. This state machine is used to give a name to each
+ // code path, such that we can assert each code path with a single word.
+ var scriptLoaderStateMachine = {
+ "scriptloader_load_source": {
+ "scriptloader_execute": {
+ "scriptloader_encode": {
+ "scriptloader_bytecode_saved": "bytecode_saved",
+ "scriptloader_bytecode_failed": "bytecode_failed"
+ },
+ "scriptloader_no_encode": "source_exec"
+ },
+ "scriptloader_evaluate_module": {
+ "scriptloader_encode": {
+ "scriptloader_bytecode_saved": "module_bytecode_saved",
+ "scriptloader_bytecode_failed": "module_bytecode_failed"
+ },
+ "scriptloader_no_encode": "module_source_exec"
+ },
+ },
+ "scriptloader_load_bytecode": {
+ "scriptloader_fallback": {
+ // Replicate the top-level state machine without
+ // "scriptloader_load_bytecode" transition.
+ "scriptloader_load_source": {
+ "scriptloader_execute": {
+ "scriptloader_encode": {
+ "scriptloader_bytecode_saved": "fallback_bytecode_saved",
+ "scriptloader_bytecode_failed": "fallback_bytecode_failed"
+ },
+ "scriptloader_no_encode": "fallback_source_exec"
+ },
+ "scriptloader_evaluate_module": {
+ "scriptloader_encode": {
+ "scriptloader_bytecode_saved": "module_fallback_bytecode_saved",
+ "scriptloader_bytecode_failed": "module_fallback_bytecode_failed",
+ },
+ "scriptloader_no_encode": "module_fallback_source_exec",
+ },
+ }
+ },
+ "scriptloader_execute": "bytecode_exec",
+ "scriptloader_evaluate_module": "module_bytecode_exec",
+ }
+ };
+
+ function WaitForScriptTagEvent(url) {
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ var stateMachine = scriptLoaderStateMachine;
+ var stateHistory = [];
+ var stateMachineResolve, stateMachineReject;
+ var statePromise = new Promise((resolve, reject) => {
+ stateMachineResolve = resolve;
+ stateMachineReject = reject;
+ });
+ var ping = 0;
+
+ // Walk the script loader state machine with the emitted events.
+ function log_event(evt) {
+ // If we have multiple script tags in the loaded source, make sure
+ // we only watch a single one.
+ if (evt.target.id != "watchme")
+ return;
+
+ dump("## ScriptLoader event: " + evt.type + "\n");
+ stateHistory.push(evt.type)
+ if (typeof stateMachine == "object")
+ stateMachine = stateMachine[evt.type];
+ if (typeof stateMachine == "string") {
+ // We arrived to a final state, report the name of it.
+ var result = stateMachine;
+ if (ping) {
+ result = `${result} & ping(=${ping})`;
+ }
+ stateMachineResolve(result);
+ } else if (stateMachine === undefined) {
+ // We followed an unknown transition, report the known history.
+ stateMachineReject(stateHistory);
+ }
+ }
+
+ var iwin = iframe.contentWindow;
+ iwin.addEventListener("scriptloader_load_source", log_event);
+ iwin.addEventListener("scriptloader_load_bytecode", log_event);
+ iwin.addEventListener("scriptloader_generate_bytecode", log_event);
+ iwin.addEventListener("scriptloader_execute", log_event);
+ iwin.addEventListener("scriptloader_evaluate_module", log_event);
+ iwin.addEventListener("scriptloader_encode", log_event);
+ iwin.addEventListener("scriptloader_no_encode", log_event);
+ iwin.addEventListener("scriptloader_bytecode_saved", log_event);
+ iwin.addEventListener("scriptloader_bytecode_failed", log_event);
+ iwin.addEventListener("scriptloader_fallback", log_event);
+ iwin.addEventListener("ping", (evt) => {
+ ping += 1;
+ dump(`## Content event: ${evt.type} (=${ping})\n`);
+ });
+ iframe.src = url;
+
+ statePromise.then(() => {
+ document.body.removeChild(iframe);
+ });
+ return statePromise;
+ }
+
+ async function basicTest(isModule) {
+ const prefix = isModule ? "module_" : "";
+ const name = isModule ? "module" : "script";
+
+ // Setting dom.expose_test_interfaces pref causes the
+ // nsScriptLoadRequest to fire event on script tags, with information
+ // about its internal state. The ScriptLoader source send events to
+ // trace these and resolve a promise with the path taken by the
+ // script loader.
+ //
+ // Setting dom.script_loader.bytecode_cache.strategy to -1 causes the
+ // nsScriptLoadRequest to force all the conditions necessary to make a
+ // script be saved as bytecode in the alternate data storage provided
+ // by the channel (necko cache).
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.bytecode_cache.enabled', true],
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.strategy', -1]
+ ]});
+
+ // Load the test page, and verify that the code path taken by the
+ // nsScriptLoadRequest corresponds to the code path which is loading a
+ // source and saving it as bytecode.
+ var stateMachineResult = WaitForScriptTagEvent(`file_${prefix}js_cache.html`);
+ assert_equals(await stateMachineResult, `${prefix}bytecode_saved`,
+ `[1-${name}] ScriptLoadRequest status after the first visit`);
+
+ // Reload the same test page, and verify that the code path taken by
+ // the nsScriptLoadRequest corresponds to the code path which is
+ // loading bytecode and executing it.
+ stateMachineResult = WaitForScriptTagEvent(`file_${prefix}js_cache.html`);
+ assert_equals(await stateMachineResult, `${prefix}bytecode_exec`,
+ `[2-${name}] ScriptLoadRequest status after the second visit`);
+
+ // Load another page which loads the same script with an SRI, while
+ // the cached bytecode does not have any. This should fallback to
+ // loading the source before saving the bytecode once more.
+ stateMachineResult = WaitForScriptTagEvent(`file_${prefix}js_cache_with_sri.html`);
+ assert_equals(await stateMachineResult, `${prefix}fallback_bytecode_saved`,
+ `[3-${name}] ScriptLoadRequest status after the SRI hash`);
+
+ // Loading a page, which has the same SRI should verify the SRI and
+ // continue by executing the bytecode.
+ var stateMachineResult1 = WaitForScriptTagEvent(`file_${prefix}js_cache_with_sri.html`);
+
+ // Loading a page which does not have a SRI while we have one in the
+ // cache should not change anything. We should also be able to load
+ // the cache simultanesouly.
+ var stateMachineResult2 = WaitForScriptTagEvent(`file_${prefix}js_cache.html`);
+
+ assert_equals(await stateMachineResult1, `${prefix}bytecode_exec`,
+ `[4-${name}] ScriptLoadRequest status after same SRI hash`);
+ assert_equals(await stateMachineResult2, `${prefix}bytecode_exec`,
+ `[5-${name}] ScriptLoadRequest status after visit with no SRI`);
+
+ if (!isModule) {
+ // Load a page that uses the same script as a module and verify that we
+ // re-parse it from source.
+ stateMachineResult = WaitForScriptTagEvent("file_js_cache_module.html");
+ assert_equals(await stateMachineResult, "module_bytecode_saved",
+ `[6-${name}] ScriptLoadRequest status for a module`);
+ } else {
+ // Load a page that uses the same module script as a regular script and
+ // verify that we re-parse it from source.
+ stateMachineResult = WaitForScriptTagEvent("file_module_js_cache_no_module.html");
+ assert_equals(await stateMachineResult, "bytecode_saved",
+ `[6-${name}] ScriptLoadRequest status for a script`);
+ }
+ }
+
+ promise_test(async function() {
+ await basicTest(false);
+ }, "Check the JS bytecode cache for script");
+
+ promise_test(async function() {
+ await basicTest(true);
+ }, "Check the JS bytecode cache for module");
+
+ promise_test(async function() {
+ // (see above)
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.bytecode_cache.enabled', true],
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.strategy', -1]
+ ]});
+
+ // The test page add a new script which generate a "ping" event, which
+ // should be recorded before the bytecode is stored in the cache.
+ var stateMachineResult =
+ WaitForScriptTagEvent("file_js_cache_save_after_load.html");
+ assert_equals(await stateMachineResult, "bytecode_saved & ping(=3)",
+ "Wait on all scripts to be executed");
+
+ }, "Save bytecode after the initialization of the page");
+
+ promise_test(async function() {
+ // (see above)
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.bytecode_cache.enabled', true],
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.strategy', -1]
+ ]});
+
+ // The test page loads a script which contains a syntax error, we should
+ // not attempt to encode any bytecode for it.
+ var stateMachineResult =
+ WaitForScriptTagEvent("file_js_cache_syntax_error.html");
+ assert_equals(await stateMachineResult, "source_exec",
+ "Check the lack of bytecode encoding");
+
+ }, "Do not save bytecode on compilation errors");
+
+ promise_test(async function() {
+ // (see above)
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.bytecode_cache.enabled', true],
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.strategy', -1],
+ ['browser.cache.jsbc_compression_level', 2]
+ ]});
+
+ // Load the test page, and verify that the code path taken by the
+ // nsScriptLoadRequest corresponds to the code path which is loading a
+ // source and saving it as compressed bytecode.
+ var stateMachineResult = WaitForScriptTagEvent(`file_js_cache.html`);
+ assert_equals(await stateMachineResult, `bytecode_saved`,
+ `[1-script] ScriptLoadRequest status after the first visit`);
+
+ // Reload the same test page, and verify that the code path taken by
+ // the nsScriptLoadRequest corresponds to the code path which is
+ // loading compressed bytecode, decompressing it, and executing it.
+ stateMachineResult = WaitForScriptTagEvent(`file_js_cache.html`);
+ assert_equals(await stateMachineResult, `bytecode_exec`,
+ `[2-script] ScriptLoadRequest status after the second visit`);
+ }, "Check the JS bytecode cache can save and load compressed bytecode");
+
+ done();
+ </script>
+</head>
+<body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=900784">Mozilla Bug 900784</a>
+</body>
+</html>
diff --git a/dom/base/test/test_script_loader_js_cache_frames.html b/dom/base/test/test_script_loader_js_cache_frames.html
new file mode 100644
index 0000000000..722038ca0f
--- /dev/null
+++ b/dom/base/test/test_script_loader_js_cache_frames.html
@@ -0,0 +1,202 @@
+<!DOCTYPE html>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1436400 -->
+<!-- The JS bytecode cache is not supposed to be observable. To make it
+ observable, the ScriptLoader is instrumented to trigger events on the
+ script tag.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for saving and loading module bytecode in/from the necko cache</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+
+// List of testcases
+//
+// src
+// HTML file loaded in iframe
+// saveEvents
+// Non-ordered multi-set of expected events dispatched during loading the
+// "save" iframe in the HTML file
+// loadEvents
+// Non-ordered multi-set of expected events dispatched during loading the
+// "load" iframe in the HTML file
+const tests = [
+ // Same module is loaded by script element in 2 frames.
+ {
+ src: "file_script_module_frames_element.html",
+ saveEvents: [
+ // file_script_module_frames_element_shared.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ loadEvents: [
+ // file_script_module_frames_element_shared.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module",
+ "test_evaluated",
+ ],
+ },
+
+ // Same module is imported in 2 frames.
+ {
+ src: "file_script_module_frames_import.html",
+ saveEvents: [
+ // file_script_module_frames_import_save.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_frames_import_shared.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ loadEvents: [
+ // file_script_module_frames_import_load.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_frames_import_shared.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Same module is dynamically imported in 2 frames.
+ {
+ src: "file_script_module_frames_dynamic.html",
+ saveEvents: [
+ // file_script_module_frames_dynamic_save.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_frames_dynamic_shared.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ loadEvents: [
+ // file_script_module_frames_dynamic_load.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_frames_dynamic_shared.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module",
+ ],
+ },
+];
+
+promise_test(async function() {
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.bytecode_cache.enabled', true],
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.strategy', -1]
+ ]});
+
+ for (const { src, saveEvents, loadEvents } of tests) {
+ const iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ const iwin = iframe.contentWindow;
+
+ dump("## Start: " + src + "\n");
+ let observedSaveEvents = [];
+ await new Promise(resolve => {
+ function logEvent(evt) {
+ const type = evt.type.replace(/^save_/, "");
+
+ dump("## ScriptLoader event: " + type + "\n");
+ observedSaveEvents.push(type);
+ if (observedSaveEvents.length == saveEvents.length) {
+ resolve();
+ }
+ }
+ iwin.addEventListener("save_scriptloader_load_source", logEvent);
+ iwin.addEventListener("save_scriptloader_load_bytecode", logEvent);
+ iwin.addEventListener("save_scriptloader_execute", logEvent);
+ iwin.addEventListener("save_scriptloader_evaluate_module", logEvent);
+ iwin.addEventListener("save_scriptloader_encode", logEvent);
+ iwin.addEventListener("save_scriptloader_no_encode", logEvent);
+ iwin.addEventListener("save_scriptloader_bytecode_saved", logEvent);
+ iwin.addEventListener("save_scriptloader_bytecode_failed", logEvent);
+ iwin.addEventListener("save_scriptloader_fallback", logEvent);
+ iwin.addEventListener("save_test_evaluated", logEvent);
+ iframe.src = src;
+ });
+
+ // The event order is non-deterministic.
+ // Just compare them as multi-set.
+ saveEvents.sort();
+ observedSaveEvents.sort();
+ assert_equals(
+ JSON.stringify(observedSaveEvents),
+ JSON.stringify(saveEvents),
+ `Expected events should be observed for ${src} while saving`);
+
+ let observedLoadEvents = [];
+ const loadFrameEventPromise = new Promise(resolve => {
+ function logEvent(evt) {
+ const type = evt.type.replace(/^load_/, "");
+
+ dump("## ScriptLoader event: " + type + "\n");
+ observedLoadEvents.push(type);
+ if (observedLoadEvents.length == loadEvents.length) {
+ resolve();
+ }
+ }
+ iwin.addEventListener("load_scriptloader_load_source", logEvent);
+ iwin.addEventListener("load_scriptloader_load_bytecode", logEvent);
+ iwin.addEventListener("load_scriptloader_execute", logEvent);
+ iwin.addEventListener("load_scriptloader_evaluate_module", logEvent);
+ iwin.addEventListener("load_scriptloader_encode", logEvent);
+ iwin.addEventListener("load_scriptloader_no_encode", logEvent);
+ iwin.addEventListener("load_scriptloader_bytecode_saved", logEvent);
+ iwin.addEventListener("load_scriptloader_bytecode_failed", logEvent);
+ iwin.addEventListener("load_scriptloader_fallback", logEvent);
+ iwin.addEventListener("load_test_evaluated", logEvent);
+
+ });
+
+ // Make sure the "load" iframe is fully loaded.
+ await iwin.loadFramePromise;
+ iwin.document.getElementById("load").contentWindow.doLoad();
+
+ await loadFrameEventPromise;
+
+ // The event order is non-deterministic.
+ // Just compare them as multi-set.
+ loadEvents.sort();
+ observedLoadEvents.sort();
+ assert_equals(
+ JSON.stringify(observedLoadEvents),
+ JSON.stringify(loadEvents),
+ `Expected events should be observed for ${src} while loading`);
+
+ document.body.removeChild(iframe);
+ }
+}, "Test module bytecode save and load");
+
+done();
+ </script>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1436400">Mozilla Bug 1436400</a>
+</body>
+</html>
diff --git a/dom/base/test/test_script_loader_js_cache_module.html b/dom/base/test/test_script_loader_js_cache_module.html
new file mode 100644
index 0000000000..8b15d91b6f
--- /dev/null
+++ b/dom/base/test/test_script_loader_js_cache_module.html
@@ -0,0 +1,537 @@
+<!DOCTYPE html>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1436400 -->
+<!-- The JS bytecode cache is not supposed to be observable. To make it
+ observable, the ScriptLoader is instrumented to trigger events on the
+ script tag.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for saving and loading module bytecode in/from the necko cache</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+
+// List of testcases
+//
+// src
+// HTML file loaded twice in an iframe
+// encodeEvents
+// Non-ordered multi-set of expected events dispatched during loading the
+// HTML file at the first time
+// decodeEvents
+// Non-ordered multi-set of expected events dispatched during loading the
+// HTML file at the second time
+const tests = [
+ // Module without import.
+ {
+ src: "file_script_module_single.html",
+ encodeEvents: [
+ // file_script_module_single.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ decodeEvents: [
+ // file_script_module_single.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module",
+ "test_evaluated",
+ ],
+ },
+
+ // Module with import.
+ {
+ src: "file_script_module_import.html",
+ encodeEvents: [
+ // file_script_module_import.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_import_imported.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ ],
+ decodeEvents: [
+ // file_script_module_import.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "test_evaluated",
+
+ // file_script_module_import_imported.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Single module is imported twice.
+ {
+ src: "file_script_module_import_multi.html",
+ encodeEvents: [
+ // file_script_module_import_multi.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_import_multi_imported_once.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_import_multi_imported_twice.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_import_multi.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "test_evaluated",
+
+ // file_script_module_import_multi_imported_once.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_import_multi_imported_twice.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Single module is imported twice from different elements.
+ {
+ src: "file_script_module_import_multi_elems.html",
+ encodeEvents: [
+ // file_script_module_import_multi_elems_1.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_import_multi_elems_2.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_import_multi_elems_imported_once_1.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_import_multi_elems_imported_once_2.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_import_multi_elems_imported_once_3.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_import_multi_elems_imported_twice.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_import_multi_elems_1.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "test_evaluated",
+
+ // file_script_module_import_multi_elems_2.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "test_evaluated",
+
+ // file_script_module_import_multi_elems_imported_once_1.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_import_multi_elems_imported_once_2.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_import_multi_elems_imported_once_3.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_import_multi_elems_imported_twice.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Single module is imported, and then loaded by element.
+ {
+ src: "file_script_module_import_and_element.html",
+ encodeEvents: [
+ // file_script_module_import_and_element.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_import_and_element_imported_1.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_import_and_element_imported_2.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_import_and_element_imported_3.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_import_and_element.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "test_evaluated",
+
+ // file_script_module_import_and_element_imported_1.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+
+ // file_script_module_import_and_element_imported_2.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_import_and_element_imported_3.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Single module is loaded by element, and then imported.
+ {
+ src: "file_script_module_element_and_import.html",
+ encodeEvents: [
+ // file_script_module_element_and_import.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_element_and_import_imported_1.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_element_and_import_imported_2.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_element_and_import_imported_3.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_element_and_import.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+ "test_evaluated",
+
+ // file_script_module_element_and_import_imported_1.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level
+
+ // file_script_module_element_and_import_imported_2.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_element_and_import_imported_3.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Module with dynamic import.
+ {
+ src: "file_script_module_dynamic_import.html",
+ encodeEvents: [
+ // file_script_module_dynamic_import.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_dynamic_import_imported.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_dynamic_import.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "test_evaluated",
+
+ // file_script_module_dynamic_import_imported.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+ ],
+ },
+
+ // Single module is imported dynamically, and then loaded by element.
+ {
+ src: "file_script_module_dynamic_and_element.html",
+ encodeEvents: [
+ // file_script_module_dynamic_and_element.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_dynamic_and_element_imported_1.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_dynamic_and_element_imported_2.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_dynamic_and_element_imported_3.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_dynamic_and_element.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "test_evaluated",
+
+ // file_script_module_dynamic_and_element_imported_1.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+
+ // file_script_module_dynamic_and_element_imported_2.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_dynamic_and_element_imported_3.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Single module is loaded by element, and then imported dynamically.
+ {
+ src: "file_script_module_element_and_dynamic.html",
+ encodeEvents: [
+ // file_script_module_element_and_dynamic.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_element_and_dynamic_imported_1.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_element_and_dynamic_imported_2.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_element_and_dynamic_imported_3.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_element_and_dynamic.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "test_evaluated",
+
+ // file_script_module_element_and_dynamic_imported_1.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+
+ // file_script_module_element_and_dynamic_imported_2.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_element_and_dynamic_imported_3.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Single module is imported dynamically, and then statically.
+ {
+ src: "file_script_module_dynamic_and_static.html",
+ encodeEvents: [
+ // file_script_module_dynamic_and_static.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_dynamic_and_static_imported_1.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_dynamic_and_static_imported_2.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_dynamic_and_static_imported_3.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_dynamic_and_static.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "test_evaluated",
+
+ // file_script_module_dynamic_and_static_imported_1.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+
+ // file_script_module_dynamic_and_static_imported_2.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_dynamic_and_static_imported_3.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+
+ // Single module is imported statically and then dynamically.
+ {
+ src: "file_script_module_static_and_dynamic.html",
+ encodeEvents: [
+ // file_script_module_static_and_dynamic.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_static_and_dynamic_imported_1.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_static_and_dynamic_imported_2.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+
+ // file_script_module_static_and_dynamic_imported_3.js
+ "scriptloader_load_source",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ ],
+ decodeEvents: [
+ // file_script_module_static_and_dynamic.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (element)
+ "test_evaluated",
+
+ // file_script_module_static_and_dynamic_imported_1.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // dispatched only for top-level (dynamic)
+
+ // file_script_module_static_and_dynamic_imported_2.js
+ "scriptloader_load_bytecode",
+
+ // file_script_module_static_and_dynamic_imported_3.js
+ "scriptloader_load_bytecode",
+ ],
+ },
+];
+
+promise_test(async function() {
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.bytecode_cache.enabled', true],
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.strategy', -1]
+ ]});
+
+ for (const { src, encodeEvents, decodeEvents } of tests) {
+ for (let i = 0; i < 2; i++) {
+ const expectedEvents = i == 0 ? encodeEvents : decodeEvents;
+
+ const iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ const iwin = iframe.contentWindow;
+
+ dump("## Start: " + src + "\n");
+ let observedEvents = [];
+ await new Promise(resolve => {
+ function logEvent(evt) {
+ if (evt.type != "test_evaluated") {
+ if (!/^watchme/.test(evt.target.id)) {
+ return;
+ }
+ }
+ dump("## ScriptLoader event: " + evt.type + "\n");
+ observedEvents.push(evt.type);
+ if (observedEvents.length == expectedEvents.length) {
+ resolve();
+ }
+ }
+ iwin.addEventListener("scriptloader_load_source", logEvent);
+ iwin.addEventListener("scriptloader_load_bytecode", logEvent);
+ iwin.addEventListener("scriptloader_execute", logEvent);
+ iwin.addEventListener("scriptloader_evaluate_module", logEvent);
+ iwin.addEventListener("scriptloader_encode", logEvent);
+ iwin.addEventListener("scriptloader_no_encode", logEvent);
+ iwin.addEventListener("scriptloader_bytecode_saved", logEvent);
+ iwin.addEventListener("scriptloader_bytecode_failed", logEvent);
+ iwin.addEventListener("scriptloader_fallback", logEvent);
+ iwin.addEventListener("test_evaluated", logEvent);
+ iframe.src = src;
+ });
+
+ // The event order is non-deterministic.
+ // Just compare them as multi-set.
+ expectedEvents.sort();
+ observedEvents.sort();
+ assert_equals(
+ JSON.stringify(observedEvents),
+ JSON.stringify(expectedEvents),
+ `Expected events should be observed for ${src} during ${i == 0 ? "encoding" : "decoding"}`);
+
+ document.body.removeChild(iframe);
+ }
+ }
+}, "Test module bytecode save and load");
+
+done();
+ </script>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1436400">Mozilla Bug 1436400</a>
+</body>
+</html>
diff --git a/dom/base/test/test_script_loader_js_cache_module_sri.html b/dom/base/test/test_script_loader_js_cache_module_sri.html
new file mode 100644
index 0000000000..9a7c7a57e8
--- /dev/null
+++ b/dom/base/test/test_script_loader_js_cache_module_sri.html
@@ -0,0 +1,425 @@
+<!DOCTYPE html>
+<html>
+<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1436400 -->
+<!-- The JS bytecode cache is not supposed to be observable. To make it
+ observable, the ScriptLoader is instrumented to trigger events on the
+ script tag.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for request fallback for SRI mismatch on module bytecode</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+
+// List of testcases
+//
+// prep
+// HTML file loaded in iframe that prepares the bytecode cache
+// prepEvents
+// Non-ordered multi-set of expected events dispatched during loading the
+// "prep" HTML file
+// src
+// HTML file loaded in iframe after preparation finishes
+// events
+// Non-ordered multi-set of expected events dispatched during loading the
+// "src" HTML file
+const tests = [
+ // 1. Module bytecode is saved with integrity
+ // 2. Module bytecode is loaded by script element with integrity
+ {
+ prep: "file_script_module_sri_basic_prep.html",
+ prepEvents: [
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_basic.html",
+ events: [
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module",
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is loaded by script element with integrity
+ {
+ prep: "file_script_module_sri_fallback_prep.html",
+ prepEvents: [
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_fallback.html",
+ events: [
+ "scriptloader_load_bytecode",
+ "scriptloader_fallback",
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is loaded by script element with wrong integrity
+ //
+ // The module script is not evaluated
+ {
+ prep: "file_script_module_sri_fallback_failure_prep.html",
+ prepEvents: [
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_fallback_failure.html",
+ events: [
+ "scriptloader_load_bytecode",
+ "scriptloader_fallback",
+ "scriptloader_load_source",
+
+ // This event is dispatched by another script, after the first module
+ // script load is terminated.
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is loaded by script element without integrity, and then
+ // loaded by script element with integrity
+ //
+ // The integrity attribute is ignored because the first request without
+ // integrity is shared between them.
+ {
+ prep: "file_script_module_sri_elem_elem_1_prep.html",
+ prepEvents: [
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_elem_elem_1.html",
+ events: [
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module",
+ "test_evaluated",
+
+ // NOTE: scriptloader_evaluate_module is dispatched even if
+ // the module is already evaluated before and it's evaluation is
+ // skipped this time.
+ "scriptloader_evaluate_module",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is loaded by script element with integrity, and then
+ // loaded by script element without integrity
+ //
+ // The request with integrity is shared between them.
+ {
+ prep: "file_script_module_sri_elem_elem_2_prep.html",
+ prepEvents: [
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_elem_elem_2.html",
+ events: [
+ "scriptloader_load_bytecode",
+ "scriptloader_fallback",
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ "scriptloader_evaluate_module",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is loaded by script element with integrity, and then
+ // imported statically.
+ //
+ // The request with integrity is shared between them.
+ {
+ prep: "file_script_module_sri_elem_import_prep.html",
+ prepEvents: [
+ // file_script_module_sri_elem_import_imported.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_elem_import.html",
+ events: [
+ // file_script_module_sri_elem_import_imported.js
+ "scriptloader_load_bytecode",
+ "scriptloader_fallback",
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_sri_elem_import.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is imported statically, and
+ // loaded by script element with integrity
+ //
+ // Even if the import is performed first, the script element's request
+ // with integrity is used because of preload.
+ {
+ prep: "file_script_module_sri_import_elem_prep.html",
+ prepEvents: [
+ // file_script_module_sri_import_elem_imported.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_import_elem.html",
+ events: [
+ // file_script_module_sri_import_elem.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_sri_import_elem_imported.js
+ "scriptloader_load_bytecode",
+ "scriptloader_fallback",
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is imported statically, and
+ // loaded by script element with integrity, without preload
+ //
+ // The request without integrity triggered by import is shared between
+ // them.
+ {
+ prep: "file_script_module_sri_import_elem_nopreload_prep.html",
+ prepEvents: [
+ // file_script_module_sri_import_elem_nopreload_imported.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_import_elem_nopreload.html",
+ events: [
+ // file_script_module_sri_import_elem_nopreload.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_sri_import_elem_nopreload_imported.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module",
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is loaded by script element with integrity, and then
+ // imported dynamically.
+ //
+ // The request with integrity is shared between them.
+ {
+ prep: "file_script_module_sri_elem_dynamic_prep.html",
+ prepEvents: [
+ // file_script_module_sri_elem_dynamic_imported.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_elem_dynamic.html",
+ events: [
+ // file_script_module_sri_elem_dynamic_imported.js
+ "scriptloader_load_bytecode",
+ "scriptloader_fallback",
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // (element)
+ "scriptloader_evaluate_module", // (dynamic)
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+
+ // file_script_module_sri_elem_dynamic.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is imported dynamically, and then
+ // loaded by script element with integrity
+ //
+ // Even if the dynamic import is performed first, the script element's
+ // request with integrity is used because of preload.
+ {
+ prep: "file_script_module_sri_dynamic_elem_prep.html",
+ prepEvents: [
+ // file_script_module_sri_dynamic_elem_imported.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_dynamic_elem.html",
+ events: [
+ // file_script_module_sri_dynamic_elem_imported.js
+ "scriptloader_load_bytecode",
+ "scriptloader_fallback",
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module", // (element)
+ "scriptloader_evaluate_module", // (dynamic)
+ "scriptloader_encode",
+ "test_evaluated",
+
+ // file_script_module_sri_dynamic_elem.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ },
+
+ // 1. Module bytecode is saved without integrity
+ // 2. Module bytecode is imported dynamically, and then
+ // loaded by script element with integrity, without preload
+ //
+ // The request without integrity triggered by dynamic import is shared
+ // between them.
+ {
+ prep: "file_script_module_sri_dynamic_elem_nopreload_prep.html",
+ prepEvents: [
+ // file_script_module_sri_dynamic_elem_nopreload_imported.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ src: "file_script_module_sri_dynamic_elem_nopreload.html",
+ events: [
+ // file_script_module_sri_dynamic_elem_nopreload_imported.js
+ "scriptloader_load_bytecode",
+ "scriptloader_evaluate_module", // (element)
+ "scriptloader_evaluate_module", // (dynamic)
+ "test_evaluated",
+
+ // file_script_module_sri_dynamic_elem_nopreload.js
+ "scriptloader_load_source",
+ "scriptloader_evaluate_module",
+ "scriptloader_encode",
+ "scriptloader_bytecode_saved",
+ "test_evaluated",
+ ],
+ },
+];
+
+promise_test(async function() {
+ await SpecialPowers.pushPrefEnv({set: [
+ ['dom.script_loader.bytecode_cache.enabled', true],
+ ['dom.expose_test_interfaces', true],
+ ['dom.script_loader.bytecode_cache.strategy', -1]
+ ]});
+
+ for (const { prep, prepEvents, src, events } of tests) {
+ for (let i = 0; i < 2; i++) {
+ const expectedEvents = i == 0 ? prepEvents : events;
+ const currentSrc = i == 0 ? prep : src;
+
+ const iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ const iwin = iframe.contentWindow;
+
+ dump("## Start: " + currentSrc + "\n");
+ let observedEvents = [];
+ await new Promise(resolve => {
+ function logEvent(evt) {
+ if (evt.type != "test_evaluated") {
+ if (!/^watchme/.test(evt.target.id)) {
+ return;
+ }
+ }
+ dump("## ScriptLoader event: " + evt.type + "\n");
+ observedEvents.push(evt.type);
+ if (observedEvents.length == expectedEvents.length) {
+ resolve();
+ }
+ }
+ iwin.addEventListener("scriptloader_load_source", logEvent);
+ iwin.addEventListener("scriptloader_load_bytecode", logEvent);
+ iwin.addEventListener("scriptloader_execute", logEvent);
+ iwin.addEventListener("scriptloader_evaluate_module", logEvent);
+ iwin.addEventListener("scriptloader_encode", logEvent);
+ iwin.addEventListener("scriptloader_no_encode", logEvent);
+ iwin.addEventListener("scriptloader_bytecode_saved", logEvent);
+ iwin.addEventListener("scriptloader_bytecode_failed", logEvent);
+ iwin.addEventListener("scriptloader_fallback", logEvent);
+ iwin.addEventListener("test_evaluated", logEvent);
+ iframe.src = currentSrc;
+ });
+
+ // The event order is non-deterministic.
+ // Just compare them as multi-set.
+ expectedEvents.sort();
+ observedEvents.sort();
+ assert_equals(
+ JSON.stringify(observedEvents),
+ JSON.stringify(expectedEvents),
+ `Expected events should be observed for ${currentSrc}`);
+
+ document.body.removeChild(iframe);
+ }
+ }
+}, "Test module bytecode save and load");
+
+done();
+ </script>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1436400">Mozilla Bug 1436400</a>
+</body>
+</html>
diff --git a/dom/base/test/test_sendQueryContentAndSelectionSetEvent.html b/dom/base/test/test_sendQueryContentAndSelectionSetEvent.html
new file mode 100644
index 0000000000..76e8168706
--- /dev/null
+++ b/dom/base/test/test_sendQueryContentAndSelectionSetEvent.html
@@ -0,0 +1,253 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for nsIDOMWindowUtils.sendQueryContentEvent() and .sendSelectionSetEvent()</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div contenteditable>abc<br>def</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+const kLineBreak = navigator.platform.indexOf("Win") == 0 ? "\r\n" : "\n";
+
+SimpleTest.waitForFocus(async () => {
+ const gUtils = window.windowUtils;
+
+ function escape(aStr)
+ {
+ var result = aStr.replace("\n", "\\n");
+ return result.replace("\r", "\\r");
+ }
+
+ function waitForFlushingIMEContentObserver() {
+ return new Promise(resolve => requestAnimationFrame(
+ () => requestAnimationFrame(resolve)
+ ));
+ }
+
+ const editor = document.querySelector("div[contenteditable]");
+ editor.focus();
+
+ // NOTE: For compatibility, calling without flags should work as with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK.
+
+ // QueryTextContent
+ var expectedStr = escape(("abc" + kLineBreak + "def").substr(2, 4));
+ var result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_CONTENT, 2, 4, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+ is(escape(result.text), expectedStr,
+ "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) got unexpected string");
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_CONTENT, 2, 4, 0, 0);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_CONTENT) should succeed");
+ is(escape(result.text), expectedStr,
+ "sendQueryContentEvent(QUERY_TEXT_CONTENT) should return same string as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+ expectedStr = escape(("abc\ndef").substr(2, 4));
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_CONTENT, 2, 4, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+ is(escape(result.text), expectedStr,
+ "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) got unexpected string");
+
+ // QueryCaretRect
+ getSelection().collapse(editor.firstChild, 0);
+
+ var caretNative = gUtils.sendQueryContentEvent(gUtils.QUERY_CARET_RECT, 6, 0, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+ ok(caretNative.succeeded,
+ "sendQueryContentEvent(QUERY_CARET_RECT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+ var caretXP = gUtils.sendQueryContentEvent(gUtils.QUERY_CARET_RECT, 6 - kLineBreak.length + 1, 0, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+ ok(caretXP.succeeded,
+ "sendQueryContentEvent(QUERY_CARET_RECT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+
+ is(caretXP.top, caretNative.top,
+ "The caret top should be same");
+ is(caretXP.left, caretNative.left,
+ "The caret left should be same");
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_CARET_RECT, 6, 0, 0, 0);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_CARET_RECT) should succeed");
+ is(result.top, caretNative.top,
+ "sendQueryContentEvent(QUERY_CARET_RECT) should return same top as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.left, caretNative.left,
+ "sendQueryContentEvent(QUERY_CARET_RECT) should return same left as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+ // QueryTextRect
+ var textRectNative = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT, 6, 1, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+ ok(textRectNative.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_RECT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+ var textRectXP = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT, 6 - kLineBreak.length + 1, 1, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+ ok(textRectXP.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_RECT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+
+ is(textRectXP.top, textRectNative.top,
+ "The text top should be same");
+ is(textRectXP.left, textRectNative.left,
+ "The text left should be same");
+ is(textRectXP.height, textRectNative.height,
+ "The text height should be same");
+ is(textRectXP.width, textRectNative.width,
+ "The text width should be same");
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT, 6, 1, 0, 0);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_RECT) should succeed");
+ is(result.top, textRectNative.top,
+ "sendQueryContentEvent(QUERY_TEXT_RECT) should return same top as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.left, textRectNative.left,
+ "sendQueryContentEvent(QUERY_TEXT_RECT) should return same left as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.height, textRectNative.height,
+ "sendQueryContentEvent(QUERY_TEXT_RECT) should return same height as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.width, textRectNative.width,
+ "sendQueryContentEvent(QUERY_TEXT_RECT) should return same width as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+ // QueryTextRectArray
+ var textRectArray = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT_ARRAY, 1, 2, 0, 0);
+ ok(textRectArray.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should succeed");
+ var textRect = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT, 1, 2, 0, 0);
+ ok(textRect.succeeded,
+ "sendQueryContentEvent(QUERY_TEXT_RECT) should succeed");
+ var left = {};
+ var top = {};
+ var width = {};
+ var height = {};
+ textRectArray.getCharacterRect(0, left, top, width, height);
+ is(top.value, textRect.top,
+ "sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same top that returns QUERY_TEXT_RECT");
+ is(left.value, textRect.left,
+ "sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same left that returns QUERY_TEXT_RECT");
+
+ var left2 = {};
+ var top2 = {};
+ var width2 = {};
+ var height2 = {};
+ textRectArray.getCharacterRect(1, left2, top2, width2, height2);
+ isfuzzy(width.value + width2.value, textRect.width, 2,
+ "sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same width that QUERY_TEXT_RECT is returned for offset 1 and 2");
+
+ is(height.value, textRect.height,
+ "sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same height that returns QUERY_TEXT_RECT");
+
+ // QueryCharacterAtOffset
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_CHARACTER_AT_POINT, 0, 0, textRectNative.left + 1, textRectNative.top + 1,
+ gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_CHARACTER_AT_POINT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+ is(result.top, textRectNative.top,
+ "The character top is wrong");
+ is(result.left, textRectNative.left,
+ "The character left is wrong");
+ is(result.height, textRectNative.height,
+ "The character height is wrong");
+ is(result.width, textRectNative.width,
+ "The character width is wrong");
+ is(result.offset, 6,
+ "The character offset is wrong");
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_CHARACTER_AT_POINT, 0, 0, textRectNative.left + 1, textRectNative.top + 1);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_CHARACTER_AT_POINT) should succeed");
+ is(result.top, textRectNative.top,
+ "The character top should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.left, textRectNative.left,
+ "The character left should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.height, textRectNative.height,
+ "The character height should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.width, textRectNative.width,
+ "The character width should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+ is(result.offset, 6,
+ "The character offset should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_CHARACTER_AT_POINT, 0, 0, textRectXP.left + 1, textRectXP.top + 1,
+ gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_CHARACTER_AT_POINT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+ is(result.top, textRectXP.top,
+ "The character top is wrong");
+ is(result.left, textRectXP.left,
+ "The character left is wrong");
+ is(result.height, textRectXP.height,
+ "The character height is wrong");
+ is(result.width, textRectXP.width,
+ "The character width is wrong");
+ is(result.offset, 6 - kLineBreak.length + 1,
+ "The character offset is wrong");
+
+ // SelectionSet and QuerySelectedText
+ await waitForFlushingIMEContentObserver();
+ var selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK);
+ ok(selectionSet,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+ expectedStr = escape(("abc" + kLineBreak + "def").substr(0, 6));
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+ ok(!result.reversed,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK) should set non-reversed selection");
+ is(escape(result.text), expectedStr,
+ "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) got unexpected string");
+
+ await waitForFlushingIMEContentObserver();
+ selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_XP_LINE_BREAK);
+ ok(selectionSet,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK) should succeed");
+ expectedStr = escape(("abc\ndef").substr(0, 6));
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+ ok(!result.reversed,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK) should set non-reversed selection");
+ is(escape(result.text), expectedStr,
+ "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) got unexpected string");
+
+ getSelection().collapse(editor, 0);
+ await waitForFlushingIMEContentObserver();
+ var selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK | gUtils.SELECTION_SET_FLAG_REVERSE);
+ ok(selectionSet,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+ ok(result.reversed,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK | SELECTION_SET_FLAG_REVERSE) should set reversed selection");
+
+ selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_XP_LINE_BREAK | gUtils.SELECTION_SET_FLAG_REVERSE);
+ ok(selectionSet,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK | SELECTION_SET_FLAG_REVERSE) should succeed");
+
+ result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+ gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+ ok(result.succeeded,
+ "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+ ok(result.reversed,
+ "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK | SELECTION_SET_FLAG_REVERSE) should set reversed selection");
+
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_sendSelectionSetEvent_with_same_range.html b/dom/base/test/test_sendSelectionSetEvent_with_same_range.html
new file mode 100644
index 0000000000..fadcbed7ad
--- /dev/null
+++ b/dom/base/test/test_sendSelectionSetEvent_with_same_range.html
@@ -0,0 +1,100 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Testing nsIDOMWindowUtils.sendSelectionSetEvent not update selection if result range is same in serialized text within the ContentEventHandler rules</title>
+<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+<script>
+"use strict";
+
+const kLineBreak = navigator.platform.indexOf("Win") == 0 ? "\r\n" : "\n";
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async () => {
+ const editingHost = document.querySelector("div[contenteditable]");
+
+ function waitForFlushingIMEContentObserver() {
+ return new Promise(resolve => requestAnimationFrame(
+ () => requestAnimationFrame(resolve)
+ ));
+ }
+
+ await (async function test_setSelection_when_selection_collapsed_at_end_of_inline_element() {
+ editingHost.innerHTML = "<b>abc</b>def";
+ getSelection().collapse(editingHost.querySelector("b").firstChild, "abc".length);
+ await waitForFlushingIMEContentObserver();
+ const ret = windowUtils.sendSelectionSetEvent(
+ 3,
+ 0,
+ SpecialPowers.Ci.nsIDOMWindowUtils.SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK
+ );
+ ok(
+ ret,
+ "test_setSelection_when_selection_collapsed_at_end_of_inline_element: eSetSelection event should be succeeded"
+ );
+ is(
+ getSelection().focusNode,
+ editingHost.querySelector("b").firstChild,
+ "test_setSelection_when_selection_collapsed_at_end_of_inline_element: focus node should not be changed from the text node in the <b>"
+ );
+ is(
+ getSelection().focusOffset,
+ "abc".length,
+ "test_setSelection_when_selection_collapsed_at_end_of_inline_element: focus offset should not be changed from end of the text node"
+ );
+ })();
+
+ await (async function test_setSelection_when_selection_collapsed_after_inline_element() {
+ editingHost.innerHTML = "<b>abc</b>def";
+ getSelection().collapse(editingHost.querySelector("b").nextSibling, 0);
+ await waitForFlushingIMEContentObserver();
+ const ret = windowUtils.sendSelectionSetEvent(
+ 3,
+ 0,
+ SpecialPowers.Ci.nsIDOMWindowUtils.SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK
+ );
+ ok(
+ ret,
+ "test_setSelection_when_selection_collapsed_after_inline_element: eSetSelection event should be succeeded"
+ );
+ is(
+ getSelection().focusNode,
+ editingHost.querySelector("b").nextSibling,
+ "test_setSelection_when_selection_collapsed_after_inline_element: focus node should not be changed from the text node after the <b>"
+ );
+ is(
+ getSelection().focusOffset,
+ 0,
+ "test_setSelection_when_selection_collapsed_after_inline_element: focus offset should not be changed from start of the text node"
+ );
+ })();
+
+ await (async function test_setSelection_when_selection_collapsed_in_empty_block_element() {
+ editingHost.innerHTML = "<p style=\"width:1em;height:1em;\"></p>\n";
+ getSelection().collapse(editingHost.querySelector("p"), 0);
+ await waitForFlushingIMEContentObserver();
+ const ret = windowUtils.sendSelectionSetEvent(
+ kLineBreak.length,
+ 0,
+ SpecialPowers.Ci.nsIDOMWindowUtils.SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK
+ );
+ ok(
+ ret,
+ "test_setSelection_when_selection_collapsed_in_empty_block_element: eSetSelection event should be succeeded"
+ );
+ is(
+ getSelection().focusNode,
+ editingHost.querySelector("p"),
+ "test_setSelection_when_selection_collapsed_in_empty_block_element: focus node should not be changed from the empty <div>"
+ );
+ })();
+
+ SimpleTest.finish();
+});
+</script>
+</head>
+<body>
+<div contenteditable></div>
+</body>
+</html>
diff --git a/dom/base/test/test_serializer_noscript.html b/dom/base/test/test_serializer_noscript.html
new file mode 100644
index 0000000000..156440e03a
--- /dev/null
+++ b/dom/base/test/test_serializer_noscript.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for document.blockParsing</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body onload=runTest();>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function checkDoc(aDoc, aScriptState) {
+ const root = aDoc.documentElement;
+ let enc = Cu.createDocumentEncoder("text/html");
+ enc.init(
+ aDoc,
+ "text/html",
+ Ci.nsIDocumentEncoder.OutputEncodeBasicEntities |
+ Ci.nsIDocumentEncoder.OutputLFLineBreak |
+ Ci.nsIDocumentEncoder.OutputBodyOnly |
+ Ci.nsIDocumentEncoder.OutputRaw
+ );
+
+ let str = enc.encodeToString();
+
+ is(str, "<body><noscript>&lt;/noscript&gt;<img></noscript>\n</body>", "Serialization matches expectation with scripting " + aScriptState);
+}
+
+function runTest() {
+ const doc = new DOMParser().parseFromString("<body><noscript>&lt;/noscript&gt;<img></noscript>\n", "text/html");
+ checkDoc(doc, "disabled");
+ checkDoc(document.getElementsByTagName("iframe")[0].contentDocument, "enabled");
+ SimpleTest.finish();
+}
+</script>
+<iframe src="file_serializer_noscript.html"></iframe>
+</body>
+</html>
diff --git a/dom/base/test/test_setInterval_from_start.html b/dom/base/test/test_setInterval_from_start.html
new file mode 100644
index 0000000000..129705c65c
--- /dev/null
+++ b/dom/base/test/test_setInterval_from_start.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1252268
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1378394</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=1378394">Mozilla Bug 1378394</a>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+// Some of our platforms are quite slow. Use very large time values to
+// try to avoid raciness.
+const burnTimeMS = 5000;
+const intervalTimeMS = 10000;
+
+// The overall interval should include our callback "burn time". So we
+// expect the delay to be the remaining time.
+const expectedDelayMS = intervalTimeMS - burnTimeMS;
+
+// Allow some margin for error because of slow test platforms.
+const allowedMarginMS = burnTimeMS / 2;
+
+let id;
+let lastEndTime;
+
+function interval()
+{
+ let start = performance.now();
+
+ if (lastEndTime !== undefined) {
+ let delta = start - lastEndTime;
+ ok(delta <= expectedDelayMS + allowedMarginMS,
+ 'interval should not fire too late');
+ ok(delta >= expectedDelayMS - allowedMarginMS,
+ 'interval should not fire too early');
+ clearInterval(id);
+ SimpleTest.finish();
+ return;
+ }
+
+ while((performance.now() - start) < burnTimeMS);
+
+ lastEndTime = performance.now();
+}
+
+id = setInterval(interval, intervalTimeMS);
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_setInterval_uncatchable_exception.html b/dom/base/test/test_setInterval_uncatchable_exception.html
new file mode 100644
index 0000000000..3a23be8d76
--- /dev/null
+++ b/dom/base/test/test_setInterval_uncatchable_exception.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1252268
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1252268</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=1252268">Mozilla Bug 1252268</a>
+
+<script type="text/javascript">
+ function go() {
+ SimpleTest.requestFlakyTimeout("I'm smarter than the test harness");
+
+ var ranOnce = false;
+ var finished = false;
+
+ var interval = setInterval(function () {
+ if (ranOnce) {
+ ok(false, "Don't execute me again!");
+ clearInterval(interval);
+ if (!finished) {
+ finished = true;
+ SimpleTest.finish();
+ }
+ } else {
+ ranOnce = true;
+ ok(true, "Ran the first time");
+ try {
+ TestFunctions.throwUncatchableException();
+ ok(false, "How did we get here!");
+ } catch (e) {
+ ok(false, "How did we get here!?");
+ }
+ }
+ }, 100);
+
+ setTimeout(function() {
+ if (!finished) {
+ finished = true;
+ SimpleTest.finish();
+ }
+ }, 1000);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_setTimeoutWith0.html b/dom/base/test/test_setTimeoutWith0.html
new file mode 100644
index 0000000000..ff098ee33a
--- /dev/null
+++ b/dom/base/test/test_setTimeoutWith0.html
@@ -0,0 +1,22 @@
+<html>
+<head>
+ <title>Test for setTimeout and strings containing 0</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script>
+
+var x = 0;
+setTimeout("x++; '\x00'; x++;");
+setTimeout(function() {
+ is(x, 2, "We want to see 2 here");
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
+
+
diff --git a/dom/base/test/test_settimeout_extra_arguments.html b/dom/base/test/test_settimeout_extra_arguments.html
new file mode 100644
index 0000000000..b790eff069
--- /dev/null
+++ b/dom/base/test/test_settimeout_extra_arguments.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for setTimeout with a string argument and more than 2 arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ t1 = async_test("setTimeout with more than 2 arguments, first argument a string, should work");
+ t2 = async_test("setInterval with more than 2 arguments, first argument a string, should work");
+ setTimeout("t1.done()", 0, {});
+ var interval = setInterval("clearInterval(interval); t2.done()", 0, {});
+</script>
diff --git a/dom/base/test/test_settimeout_inner.html b/dom/base/test/test_settimeout_inner.html
new file mode 100644
index 0000000000..aeda2cdc88
--- /dev/null
+++ b/dom/base/test/test_settimeout_inner.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=936129
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 936129</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 936129 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function test1Done()
+ {
+ ok(true, "Bareword setTimeout should work after calling document.open().");
+
+ var iframe = document.getElementById("testFrame");
+ iframe.onload = function () {
+ window.runTest2 = iframe.contentWindow.runTest2;
+ iframe.onload = function () {
+ window.runTest2();
+ setTimeout(allDone);
+ }
+
+ // Per whatwg spec, "If the src attribute and the srcdoc attribute are
+ // both specified together, the srcdoc attribute takes priority."
+ //
+ // So if we were to use src attribute here, it will be considered as a
+ // no-op, so simply use a simple srcdoc here.
+ iframe.srcdoc = "<html></html>";
+ }
+ iframe.srcdoc = "<script>function runTest2() { setTimeout('parent.test2Done()'); };<" + "/script>";
+ }
+ window.test2DoneCalled = false;
+ function test2Done()
+ {
+ window.test2DoneCalled = true;
+ }
+ function allDone()
+ {
+ ok(!window.test2DoneCalled, "Bareword setTimeout should be a noop after the document for the window context that it's called on isn't active anymore.");
+
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=936129">Mozilla Bug 936129</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id="testFrame" src="file_settimeout_inner.html"></iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_setting_opener.html b/dom/base/test/test_setting_opener.html
new file mode 100644
index 0000000000..3021c2d0de
--- /dev/null
+++ b/dom/base/test/test_setting_opener.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=868996
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 868996</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 868996 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var sb1, sb2;
+ var Cu = SpecialPowers.Cu;
+
+ function testOpenerSet() {
+ // Use setTimeout to make the relevant onerror run in this window
+ var win = window.open("file1_setting_opener.html");
+ // A sandbox for the window
+ sb1 = new Cu.Sandbox(win, {wantXrays: true })
+ sb1.win = win
+ // And a sandbox using the expanded principal.
+ sb2 = new Cu.Sandbox([win], {wantXrays: true })
+ sb2.win = win
+ }
+
+ function evalsb(str, sb) {
+ // Have to unwrap() to get objects we care about
+ return SpecialPowers.unwrap(Cu.evalInSandbox(str, sb));
+ }
+
+ function basicOpenerTest(win) {
+ is(win.opener, window, "Opening a window should give it the right opener");
+ is(evalsb("win.opener", sb1), window,
+ "Reading opener in sandbox 1 should work");
+ is(evalsb("win.opener", sb2), window,
+ "Reading opener in sandbox 2 should work");
+
+ win.opener = $("x").contentWindow;
+ evalsb("win.opener = win.opener.document.getElementById('y').contentWindow", sb1);
+ evalsb("win.opener = win.opener.document.getElementById('z').contentWindow", sb2);
+
+ is(win.opener, $("x").contentWindow, "Should be able to set an opener to a different window");
+ is(evalsb("win.opener", sb1), $("y").contentWindow,
+ "Should be able to set the opener to a different window in a sandbox one");
+ is(evalsb("win.opener", sb2), $("z").contentWindow,
+ "Should be able to set the opener to a different window in a sandbox two");
+
+ win.location = "file2_setting_opener.html";
+ }
+
+ function continueOpenerTest(win) {
+ is(win.opener, window, "Navigating a window should have reset the opener we stashed on it temporarily");
+ is(evalsb("win.opener", sb1), window,
+ "Navigating a window should have reset the opener in sb1");
+ is(evalsb("win.opener", sb2), window,
+ "Navigating a window should have reset the opener in sb2");
+
+ win.opener = 5;
+ evalsb("win.opener = 5", sb1);
+ evalsb("win.opener = 5", sb2);
+ is(win.opener, 5, "Should be able to set an opener to a primitive");
+ is(evalsb("win.opener", sb1), 5,
+ "Should be able to set the opener to a primitive in a sandbox one");
+ is(evalsb("win.opener", sb2), 5,
+ "Should be able to set the opener to a primitive in a sandbox two");
+ win.location = "file3_setting_opener.html";
+ }
+
+ function continueOpenerTest2(win) {
+ is(win.opener, window,
+ "Navigating a window again should have reset the opener we stashed on it temporarily");
+ is(evalsb("win.opener", sb1), window,
+ "Navigating a window again should have reset the opener in sb1");
+ is(evalsb("win.opener", sb2), window,
+ "Navigating a window again should have reset the opener in sb2");
+
+ win.opener = null;
+ is(win.opener, null, "Should be able to set the opener to null");
+ is(evalsb("win.opener", sb1), null,
+ "Setting the opener to null should be visible in sb1");
+ is(evalsb("win.opener", sb2), null,
+ "Setting the opener to null should be visible in sb2");
+
+ win.location = "file4_setting_opener.html";
+ // Now poll for that load, since we have no way for the window to
+ // communicate with us now
+ setTimeout(checkForLoad, 0, win);
+ }
+
+ function checkForLoad(win) {
+ if (!win.document.documentElement ||
+ win.document.documentElement.innerText != "Loaded") {
+ setTimeout(checkForLoad, 0, win);
+ return;
+ }
+
+ is(win.opener, null, "Null opener should persist across navigations");
+ is(evalsb("win.opener", sb1), null,
+ "Null opener should persist across navigations in sb1");
+ is(evalsb("win.opener", sb2), null,
+ "Null opener should persist across navigations in sb2");
+
+ win.close();
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(testOpenerSet);
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=868996">Mozilla Bug 868996</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id="x"></iframe>
+<iframe id="y"></iframe>
+<iframe id="z"></iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_shared_compartment1.html b/dom/base/test/test_shared_compartment1.html
new file mode 100644
index 0000000000..c86eacb0a8
--- /dev/null
+++ b/dom/base/test/test_shared_compartment1.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1530608
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1530608</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 1530608 **/
+ SimpleTest.waitForExplicitFinish();
+
+ var Cu = SpecialPowers.Cu;
+ var isSameCompartment = Cu.getJSTestingFunctions().isSameCompartment;
+
+ var testsDone = 0;
+ function finishIfDone() {
+ testsDone++;
+ if (testsDone === 4) {
+ SimpleTest.finish();
+ }
+ }
+
+ // Test 1: same-origin iframe.
+ function testFrame1() {
+ var frameWin = document.getElementById("frame1").contentWindow;
+ ok(isSameCompartment(window, frameWin),
+ "Same-origin iframe must be same-compartment");
+ finishIfDone();
+ }
+
+ // Test 2: cross-origin iframe.
+ function testFrame2() {
+ var frameWin = document.getElementById("frame2").contentWindow;
+ ok(!isSameCompartment(window, frameWin),
+ "Cross-origin iframe must be cross-compartment");
+ finishIfDone();
+ }
+
+ // Test 3: same-site, cross-origin iframe.
+ function testFrame3() {
+ var frame = document.getElementById("frame3");
+ ok(!isSameCompartment(window, frame.contentWindow),
+ "Same-site cross-origin iframe must be cross-compartment");
+
+ // Now load a same-origin page in this iframe.
+ frame.onload = function() {
+ ok(isSameCompartment(window, frame.contentWindow),
+ "Frame must be same-compartment now");
+ finishIfDone();
+ };
+ frame.src = "file_empty.html";
+ }
+
+ // Test 4: dynamically created iframe.
+ addLoadEvent(function() {
+ var frame = document.createElement("iframe");
+ document.body.appendChild(frame);
+ ok(isSameCompartment(window, frame.contentWindow),
+ "Newly created iframe must be same-compartment");
+ finishIfDone();
+ });
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1530608">Mozilla Bug 1530608</a>
+
+<iframe id="frame1" onload="testFrame1()" src="file_empty.html"></iframe>
+<iframe id="frame2" onload="testFrame2()" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html"></iframe>
+<iframe id="frame3" onload="testFrame3()" src="http://test1.mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_empty.html"></iframe>
+
+</body>
+</html>
diff --git a/dom/base/test/test_shared_compartment2.html b/dom/base/test/test_shared_compartment2.html
new file mode 100644
index 0000000000..44f605d09a
--- /dev/null
+++ b/dom/base/test/test_shared_compartment2.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1530608
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1530608</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 1530608 **/
+ SimpleTest.waitForExplicitFinish();
+
+ // We have the following origins:
+ //
+ // 1: this page: mochi.test:8888
+ // 2: iframe: test1.mochi.test:8888
+ // 3: inner iframe: mochi.test:8888
+ //
+ // Test that 1 and 2 are cross-compartment (because cross-origin), but 1 and 3
+ // are same-compartment.
+
+ function go(innerWin) {
+ var Cu = SpecialPowers.Cu;
+ var isSameCompartment = Cu.getJSTestingFunctions().isSameCompartment;
+
+ var frame = document.getElementById("frame");
+ ok(!isSameCompartment(window, frame.contentWindow),
+ "Cross-origin iframe must be cross-compartment");
+
+ ok(isSameCompartment(window, innerWin),
+ "Same-origin inner iframe must be same-compartment");
+
+ SimpleTest.finish();
+ }
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1530608">Mozilla Bug 1530608</a>
+
+<iframe id="frame" src="http://test1.mochi.test:8888/tests/dom/base/test/iframe_shared_compartment2a.html"></iframe>
+
+</body>
+</html>
diff --git a/dom/base/test/test_structuredclone_backref.html b/dom/base/test/test_structuredclone_backref.html
new file mode 100644
index 0000000000..6b31582787
--- /dev/null
+++ b/dom/base/test/test_structuredclone_backref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1538622">Mozilla Bug 1538622</a>
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ let o1 = new ImageData(25, 1),
+ o2 = new ImageData(50, 1),
+ o3 = new ImageData(75, 1),
+ o4 = new ImageData(100, 1);
+
+ let data = {
+ img1: o1,
+ img2: o2,
+ img3: o3,
+ img4: o4,
+ img5: o4,
+ };
+
+ window.addEventListener("message", windowMessage);
+
+ window.postMessage(data);
+
+ function windowMessage(e) {
+ let dataCopied = e.data;
+ ok(dataCopied.img5 instanceof ImageData, "backref ImageData should still be an ImageData");
+ is(dataCopied.img5, dataCopied.img4, "backref ImageData should be the referenced one");
+ SimpleTest.finish();
+ }
+</script>
diff --git a/dom/base/test/test_structuredclone_error.html b/dom/base/test/test_structuredclone_error.html
new file mode 100644
index 0000000000..c682cff01d
--- /dev/null
+++ b/dom/base/test/test_structuredclone_error.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=XXX">Mozilla Bug XXX</a>
+
+<script>
+ const tests = [
+ {obj: (() => {}), msg: "Function object could not be cloned."},
+ {obj: document.body, msg: "HTMLBodyElement object could not be cloned."},
+ {obj: {foo: new Audio()}, msg: "HTMLAudioElement object could not be cloned."},
+ ]
+
+ for (const test of tests) {
+ let message = undefined;
+ try {
+ structuredClone(test.obj);
+ } catch (e) {
+ message = e.message;
+ }
+
+ is(message, test.msg, 'Threw correct DataCloneError');
+ }
+</script>
diff --git a/dom/base/test/test_style_cssText.html b/dom/base/test/test_style_cssText.html
new file mode 100644
index 0000000000..869063020a
--- /dev/null
+++ b/dom/base/test/test_style_cssText.html
@@ -0,0 +1,85 @@
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Test for Bug 1391169</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<style id="style"></style>
+</head>
+<body>
+<pre id="log">
+Log is:
+</pre>
+<script>
+let styleElement = document.getElementById("style");
+let logElement = document.getElementById("log");
+console.log("logElement is " + logElement);
+
+function log(text)
+{
+ logElement.innerHTML += text + "\n";
+}
+
+function textContentToCssText(text)
+{
+ // Pass input in via textContent.
+ styleElement.textContent = text;
+
+ // Read output from concatenated cssText of all rules.
+ let s = "";
+ let rules = document.styleSheets[1].cssRules;
+ for (let i = 0; i < rules.length; ++i) {
+ s += rules.item(i).cssText;
+ }
+ return s;
+}
+
+function noWhitespace(text)
+{
+ return text.replace(/\s/g, "");
+}
+
+function testData(input)
+{
+ let text;
+ let pass1Goal;
+ if (typeof(input) == "string") {
+ // Only text data, assume characters should be the same.
+ text = input;
+ pass1Goal = input;
+ } else {
+ [text, pass1Goal] = input;
+ }
+
+ let pass1Text = textContentToCssText(text);
+ is(noWhitespace(pass1Text), noWhitespace(pass1Goal), "textContent --> cssText correct characters emitted with input \"" + text + "\"");
+
+ let pass2Text = textContentToCssText(pass1Text);
+ is(pass2Text, pass1Text, "textContent --> cssText roundtrip with input \"" + text + "\"");
+
+ log(text + " --> " + pass1Text + " --> " + pass2Text);
+}
+
+let data = [
+ "*{}",
+ "* *{}",
+ "* > *{}",
+ "*>*{}",
+ "* * *{}",
+ "* > * > *{}",
+ "* + *{}",
+ "* ~ *{}",
+ ["*|*{}", "*{}"],
+ ["*|* > *{}", "* > *{}"],
+ "#tag{}",
+ "tag{}",
+ "@namespace tag url(\"fakeURL\"); tag|*{}",
+ "@namespace tag url(\"fakeURL\"); tag|* + *{}",
+];
+
+for (let i = 0; i < data.length; i++) {
+ testData(data[i]);
+}
+</script>
+</body>
+</html>
diff --git a/dom/base/test/test_suppressed_events_and_scrolling.html b/dom/base/test/test_suppressed_events_and_scrolling.html
new file mode 100644
index 0000000000..2a1d5ea493
--- /dev/null
+++ b/dom/base/test/test_suppressed_events_and_scrolling.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test event suppression and scrolling</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ function run() {
+ let testWin = window.open("file_suppressed_events_and_scrolling.html");
+ // The order of xhrDone and didScroll is random.
+ let xhrDone = false;
+ let didScroll = false;
+ window.onmessage = function(e) {
+ let iframeWindow = testWin.document.body.firstChild.contentWindow;
+ info(e.data);
+ if (e.data == "doscroll") {
+ iframeWindow.scrollTo(0, 1500);
+ } else if (e.data == "xhr_done") {
+ xhrDone = true;
+ if (didScroll) {
+ iframeWindow.scrollTo(0, 3000);
+ }
+ } else if (e.data == "didscroll") {
+ if (didScroll && xhrDone) {
+ // We got the second scroll event.
+ ok(true, "Should have got two scroll events");
+ testWin.close();
+ SimpleTest.finish();
+ }
+ didScroll = true;
+ if (xhrDone) {
+ iframeWindow.scrollTo(0, 3000);
+ }
+ }
+ }
+ }
+ </script>
+</head>
+<body onload="run()">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_suppressed_events_nested_iframe.html b/dom/base/test/test_suppressed_events_nested_iframe.html
new file mode 100644
index 0000000000..1d31c7c5d6
--- /dev/null
+++ b/dom/base/test/test_suppressed_events_nested_iframe.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1730117
+-->
+<head>
+ <title>Test event suppression on nested iframe</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=1730117">Mozilla Bug 1730117</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+function waitForMessage(aMsg) {
+ return new Promise((aResolve) => {
+ window.addEventListener("message", function handler(e) {
+ info(`receive: ${e.data}`);
+ if (e.data != aMsg) {
+ return;
+ }
+
+ window.removeEventListener("message", handler);
+ aResolve();
+ });
+ });
+}
+
+/** Test for Bug 1730117 **/
+
+add_task(async function test_sync_xhr() {
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["test.events.async.enabled", true],
+ ["dom.events.coalesce.mousemove", false],
+ ]});
+
+ let w = window.open("file_suppressed_events_top_xhr.html");
+ await waitForMessage("done");
+ w.close();
+});
+
+add_task(async function test_modalstate() {
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["test.events.async.enabled", false],
+ ["dom.events.coalesce.mousemove", false],
+ ]});
+
+ let w = window.open("file_suppressed_events_top_modalstate.html");
+ await waitForMessage("done");
+ w.close();
+});
+
+add_task(async function test_suppress_event_handling() {
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["test.events.async.enabled", false],
+ ["dom.events.coalesce.mousemove", false],
+ ]});
+
+ let w = window.open("file_suppressed_events_top.html");
+ await waitForMessage("done");
+ w.close();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_suppressed_microtasks.html b/dom/base/test/test_suppressed_microtasks.html
new file mode 100644
index 0000000000..f5d3336386
--- /dev/null
+++ b/dom/base/test/test_suppressed_microtasks.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test microtask suppression</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ var previousTask = -1;
+ function test() {
+ let win = window.open("about:blank");
+ win.onload = function() {
+ win.onmessage = function() {
+ win.start = win.performance.now();
+ win.didRunMicrotask = false;
+ win.onmessage = function() {
+ ok(win.didRunMicrotask, "Should have run a microtask.");
+ let period = win.performance.now() - win.start;
+ win.opener.ok(
+ period < 200,
+ "Running a task should be fast. Took " + period + "ms.");
+ win.onmessage = null;
+ }
+ win.queueMicrotask(function() { win.didRunMicrotask = true; });
+ win.postMessage("measurementMessage", "*");
+ }
+ win.postMessage("initialMessage", "*");
+
+ const last = 500000;
+ for (let i = 0; i < last + 1; ++i) {
+ window.queueMicrotask(function() {
+ // Check that once microtasks are unsuppressed, they are handled in
+ // the correct order.
+ if (previousTask != i - 1) {
+ // Explicitly optimize out cases which pass.
+ ok(false, "Microtasks should be handled in order.");
+ }
+ previousTask = i;
+ if (i == last) {
+ win.close();
+ SimpleTest.finish();
+ }
+ });
+ }
+
+ // Synchronous XMLHttpRequest suppresses microtasks.
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "slow.sjs", false);
+ xhr.send();
+ is(previousTask, -1, "Shouldn't have run microtasks during a sync XHR.");
+ }
+ }
+ </script>
+</head>
+<body onload="test()">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_text_wholeText.html b/dom/base/test/test_text_wholeText.html
new file mode 100644
index 0000000000..48ba08de58
--- /dev/null
+++ b/dom/base/test/test_text_wholeText.html
@@ -0,0 +1,232 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=421765
+-->
+<head>
+ <title>Text.wholeText tests</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=421765">Mozilla Bug 421765</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe id="xmlDocument" src="wholeTexty-helper.xml"></iframe>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 421765 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var xmlDoc;
+
+function text(t) { return document.createTextNode(t); }
+function element() { return document.createElement("div"); }
+function cdata(t)
+{
+ xmlDoc = $("xmlDocument").contentDocument;
+ // document.createCDATASection isn't implemented; clone for the win
+ var node = xmlDoc.documentElement.firstChild.cloneNode(false);
+ is(node.nodeType, Node.CDATA_SECTION_NODE,
+ "er, why isn't this a CDATA section node?");
+ node.data = t;
+ return node;
+}
+
+
+function firstTests()
+{
+ var outer = element();
+ var first = text("first");
+ var second = element();
+ second.appendChild(text("element contents"));
+ outer.appendChild(first);
+ outer.appendChild(second);
+
+ is(first.wholeText, "first", "wrong wholeText for first");
+
+ var insertedText = text("-continued");
+ outer.insertBefore(insertedText, second);
+
+ is(first.wholeText, "first-continued",
+ "wrong wholeText for first after insertedText insertion");
+ is(insertedText.wholeText, "first-continued",
+ "wrong wholeText for insertedText after insertedText insertion");
+
+ var cdataNode = cdata("zero-")
+ outer.insertBefore(cdataNode, first);
+
+ is(first.wholeText, "zero-first-continued",
+ "wrong wholeText for first after cdataNode insertion");
+ is(cdataNode.wholeText, "zero-first-continued",
+ "wrong wholeText for cdataNode after cdataNode insertion");
+ is(insertedText.wholeText, "zero-first-continued",
+ "wrong wholeText for insertedText after cdataNode insertion");
+
+ outer.insertBefore(element(), first);
+
+ is(first.wholeText, "first-continued",
+ "wrong wholeText for first after element insertion");
+ is(cdataNode.wholeText, "zero-",
+ "wrong wholeText for cdataNode after element insertion");
+ is(insertedText.wholeText, "first-continued",
+ "wrong wholeText for insertedText after element insertion");
+
+ var cdataNode2 = cdata("-interrupted");
+ outer.insertBefore(cdataNode2, insertedText);
+
+ is(first.wholeText, "first-interrupted-continued",
+ "wrong wholeText for first after cdataNode2 insertion");
+ is(cdataNode2.wholeText, "first-interrupted-continued",
+ "wrong wholeText for cdataNode2 after cdataNode2 insertion");
+ is(insertedText.wholeText, "first-interrupted-continued",
+ "wrong wholeText for insertedText after cdataNode2 insertion");
+}
+
+function middleTests()
+{
+ var outer = element();
+ var first = element();
+ var last = element();
+ var middle = text("middle");
+ first.appendChild(text("first element contents"));
+ last.appendChild(text("last element contents"));
+ outer.appendChild(first);
+ outer.appendChild(middle);
+ outer.appendChild(last);
+
+ is(middle.wholeText, "middle", "wrong wholeText for middle");
+
+ var beforeMiddle = text("before-");
+ outer.insertBefore(beforeMiddle, middle);
+
+ is(middle.wholeText, "before-middle",
+ "wrong wholeText for middle after beforeMiddle insertion");
+ is(beforeMiddle.wholeText, "before-middle",
+ "wrong wholeText for beforeMiddle after beforeMiddle insertion");
+
+ var midElement = element();
+ midElement.appendChild(text("middle element"));
+ outer.insertBefore(midElement, middle);
+
+ is(middle.wholeText, "middle",
+ "wrong wholeText for middle after midElement insertion");
+ is(beforeMiddle.wholeText, "before-",
+ "wrong wholeText for beforeMiddle after midElement insertion");
+
+ var cdataNode = cdata("after");
+ outer.insertBefore(cdataNode, midElement);
+
+ is(cdataNode.wholeText, "before-after",
+ "wrong wholeText for cdataNode after cdataNode insertion");
+ is(beforeMiddle.wholeText, "before-after",
+ "wrong wholeText for beforeMiddle after cdataNode insertion");
+ is(middle.wholeText, "middle",
+ "wrong wholeText for middle after cdataNode insertion");
+
+ var cdataNode2 = cdata("before-");
+ outer.insertBefore(cdataNode2, middle);
+
+ is(cdataNode.wholeText, "before-after",
+ "wrong wholeText for cdataNode after cdataNode2 insertion");
+ is(beforeMiddle.wholeText, "before-after",
+ "wrong wholeText for beforeMiddle after cdataNode2 insertion");
+ is(cdataNode2.wholeText, "before-middle",
+ "wrong wholeText for middle after cdataNode2 insertion");
+ is(middle.wholeText, "before-middle",
+ "wrong wholeText for middle after cdataNode2 insertion");
+}
+
+function lastTests()
+{
+ var outer = element();
+ var first = element();
+ var second = text("second");
+ first.appendChild(text("element contents"));
+ outer.appendChild(first);
+ outer.appendChild(second);
+
+ is(second.wholeText, "second", "wrong wholeText for second");
+
+ var insertedText = text("before-");
+ outer.insertBefore(insertedText, second);
+
+ is(second.wholeText, "before-second",
+ "wrong wholeText for second after insertedText insertion");
+ is(insertedText.wholeText, "before-second",
+ "wrong wholeText for insertedText after insertedText insertion");
+
+ var cdataNode = cdata("zero-")
+ outer.insertBefore(cdataNode, insertedText);
+
+ is(cdataNode.wholeText, "zero-before-second",
+ "wrong wholeText for cdataNode after cdataNode insertion");
+ is(second.wholeText, "zero-before-second",
+ "wrong wholeText for second after cdataNode insertion");
+ is(insertedText.wholeText, "zero-before-second",
+ "wrong wholeText for insertedText after cdataNode insertion");
+
+ outer.insertBefore(element(), second);
+
+ is(second.wholeText, "second",
+ "wrong wholeText for second after element insertion");
+ is(cdataNode.wholeText, "zero-before-",
+ "wrong wholeText for cdataNode after element insertion");
+ is(insertedText.wholeText, "zero-before-",
+ "wrong wholeText for insertedText after element insertion");
+
+ var cdataNode2 = cdata("interrupted-");
+ outer.insertBefore(cdataNode2, insertedText);
+
+ is(second.wholeText, "second",
+ "wrong wholeText for second after cdataNode2 insertion");
+ is(cdataNode2.wholeText, "zero-interrupted-before-",
+ "wrong wholeText for cdataNode2 after cdataNode2 insertion");
+ is(insertedText.wholeText, "zero-interrupted-before-",
+ "wrong wholeText for insertedText after cdataNode2 insertion");
+}
+
+function noParentTests()
+{
+ var textNode = text("foobar");
+ is(textNode.wholeText, textNode.data,
+ "orphaned textNode should have wholeText == data");
+ is(textNode.wholeText, "foobar",
+ "orphaned textNode should have wholeText == 'foobar'");
+
+ var cdataSection = cdata("baz");
+ is(cdataSection.wholeText, cdataSection.data,
+ "orphaned cdatasection should have wholeText == data");
+ is(cdataSection.wholeText, "baz",
+ "orphaned cdatasection should have wholeText == data");
+}
+
+function tests()
+{
+ try
+ {
+ firstTests();
+ middleTests();
+ lastTests();
+ noParentTests();
+ }
+ catch (e)
+ {
+ ok(false, "error thrown: " + e);
+ }
+ finally
+ {
+ SimpleTest.finish();
+ }
+}
+
+window.addEventListener("load", tests);
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_textnode_normalize_in_selection.html b/dom/base/test/test_textnode_normalize_in_selection.html
new file mode 100644
index 0000000000..75d5ed0032
--- /dev/null
+++ b/dom/base/test/test_textnode_normalize_in_selection.html
@@ -0,0 +1,201 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=804784
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 804784</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=804784">Mozilla Bug 804784</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 804784 **/
+
+var sel = document.getSelection();
+var flush = true;
+var dry = true;
+var run = "";
+var empty_range;
+var empty_first_text_range;
+var empty_last_text_range;
+var full_range;
+
+function check(range, expected, test)
+{
+ is(""+range, expected, test);
+ is(""+empty_range, "", "empty range test after: "+test);
+ is(""+empty_first_text_range, "", "empty first text range test after: "+test);
+ if (empty_last_text_range) is(""+empty_last_text_range, "", "empty last text range test after: "+test);
+ is(""+full_range, full_range.startContainer.textContent, "full range test after: "+test);
+}
+
+function newDiv()
+{
+ var div = document.createElement('div');
+ for (var i = 0; i < arguments.length; ++i) {
+ div.appendChild(document.createTextNode(arguments[i]));
+ }
+ document.body.appendChild(div)
+ empty_range = document.createRange();
+ empty_range.setStart(div,0);
+ empty_range.setEnd(div,0);
+ var firstTextNode = div.childNodes[0];
+ var lastTextNode = div.childNodes[div.childNodes.length - 1];
+ empty_first_text_range = document.createRange();
+ empty_first_text_range.setStart(firstTextNode,0);
+ empty_first_text_range.setEnd(firstTextNode,0);
+ empty_last_text_range = null;
+ if (firstTextNode != lastTextNode) {
+ empty_last_text_range = document.createRange();
+ empty_last_text_range.setStart(lastTextNode,0);
+ empty_last_text_range.setEnd(lastTextNode,0);
+ }
+ full_range = document.createRange();
+ full_range.setStart(div,0);
+ full_range.setEnd(div,div.childNodes.length);
+ return div;
+}
+
+function selEnd(div,child,index,s)
+{
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(start, index);
+ r.setEnd(div, div.childNodes.length);
+ if (!dry) div.normalize();
+ check(r,s,run+" selEnd "+child+","+index);
+}
+
+function selStart(div,child,index,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(div, 0);
+ r.setEnd(start, index);
+ if (!dry) div.normalize();
+ check(r,s,run+" selStart "+child+","+index);
+}
+
+function selMiddleStart(div,child,index,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(div, 1);
+ r.setEnd(start, index);
+ div.normalize();
+ check(r,s,run+" selMiddleStart "+child+","+index);
+}
+
+function selMiddleEnd(div,child,index,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(start, index);
+ r.setEnd(div, 2);
+ if (!dry) div.normalize();
+ check(r,s,run+" selMiddleEnd "+child+","+index);
+}
+
+function mergeBefore(div,child,index,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(div, 1);
+ r.setEnd(start, index);
+ if (!dry) div.normalize();
+ check(r,s,run+" mergeBefore "+child+","+index);
+}
+
+function runTests(s)
+{
+ run = s+":";
+ selEnd(newDiv('111'), 0,0,'111');
+ selEnd(newDiv('111'), 0,1,'11');
+ selEnd(newDiv('111'), 0,2,'1');
+ selEnd(newDiv(''), 0,0,'');
+ selEnd(newDiv('',''), 1,0,'');
+ selEnd(newDiv('','',''), 1,0,'');
+ selEnd(newDiv('111','222'), 0,1,'11222');
+ selEnd(newDiv('111','222'), 0,2,'1222');
+ selEnd(newDiv('111','222'), 1,1,'22');
+ selEnd(newDiv('','222'), 1,2,'2');
+ selEnd(newDiv('111',''), 0,1,'11');
+ selEnd(newDiv('111','222'), 1,2,'2');
+ selEnd(newDiv('111','222','333'), 1,1,'22333');
+ selEnd(newDiv('111','222','333'), 1,2,'2333');
+ selEnd(newDiv('111','','333'), 0,2,'1333');
+ selEnd(newDiv('111','','333'), 1,0,'333');
+ selEnd(newDiv('111','','333'), 2,0,'333');
+
+ selStart(newDiv('111'), 0,0,'');
+ selStart(newDiv('111'), 0,1,'1');
+ selStart(newDiv('111'), 0,2,'11');
+ selStart(newDiv(''), 0,0,'');
+ selStart(newDiv('111','222'), 0,1,'1');
+ selStart(newDiv('111','222'), 0,2,'11');
+ selStart(newDiv('111','222'), 1,1,'1112');
+ selStart(newDiv('111','222'), 1,2,'11122');
+ selStart(newDiv('111',''), 1,0,'111');
+ selStart(newDiv('111',''), 0,2,'11');
+ selStart(newDiv('111','222','333'), 1,1,'1112');
+ selStart(newDiv('111','222','333'), 1,2,'11122');
+ selStart(newDiv('111','222','333'), 1,2,'11122');
+ selStart(newDiv('111','','333'), 1,0,'111');
+
+ selMiddleStart(newDiv('111','222','333'), 1,1,'2');
+ selMiddleStart(newDiv('111','222','333'), 1,2,'22');
+ selMiddleStart(newDiv('111','222','333'), 2,1,'2223');
+ selMiddleStart(newDiv('111','222','333'), 2,2,'22233');
+ selMiddleStart(newDiv('111','','333'), 2,2,'33');
+ selMiddleStart(newDiv('111','222',''), 2,0,'222');
+
+ selMiddleEnd(newDiv('111','222','333'), 0,1,'11222');
+ selMiddleEnd(newDiv('111','222','333'), 0,2,'1222');
+ selMiddleEnd(newDiv('111','222','333'), 1,1,'22');
+ selMiddleEnd(newDiv('111','222','333'), 1,2,'2');
+ selMiddleEnd(newDiv('111','','333'), 1,0,'');
+ selMiddleEnd(newDiv('','222','333'), 0,0,'222');
+
+ mergeBefore(newDiv('111','222'), 1,1,'2');
+ mergeBefore(newDiv('111','222','333'), 1,2,'22');
+ mergeBefore(newDiv('111','222','333'), 2,1,'2223');
+ mergeBefore(newDiv('111','222','333'), 2,2,'22233');
+ mergeBefore(newDiv('111','','333'), 2,0,'');
+ mergeBefore(newDiv('111','','333'), 2,2,'33');
+}
+
+function boom()
+{
+ runTests("dry run"); // this is to verify the result strings without normalize()
+ dry = false;
+ flush = false;
+ runTests("no flush");
+ flush = true;
+ runTests("flush");
+}
+
+boom();
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_textnode_split_in_selection.html b/dom/base/test/test_textnode_split_in_selection.html
new file mode 100644
index 0000000000..2bd5c49201
--- /dev/null
+++ b/dom/base/test/test_textnode_split_in_selection.html
@@ -0,0 +1,221 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=803924
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 803924</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=803924">Mozilla Bug 803924</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 803924 **/
+
+var sel = document.getSelection();
+var flush = true;
+var dry = true;
+var run = "";
+var empty_range;
+var empty_first_text_range;
+var empty_last_text_range;
+var full_range;
+
+function check(range, expected, test)
+{
+ is(""+range, expected, test);
+ is(""+empty_range, "", "empty range test after: "+test);
+ is(""+empty_first_text_range, "", "empty first text range test after: "+test);
+ if (empty_last_text_range) is(""+empty_last_text_range, "", "empty last text range test after: "+test);
+ is(""+full_range, full_range.startContainer.textContent, "full range test after: "+test);
+}
+
+function newDiv()
+{
+ var div = document.createElement('div');
+ for (var i = 0; i < arguments.length; ++i) {
+ div.appendChild(document.createTextNode(arguments[i]));
+ }
+ document.body.appendChild(div)
+ empty_range = document.createRange();
+ empty_range.setStart(div,0);
+ empty_range.setEnd(div,0);
+ var firstTextNode = div.childNodes[0];
+ var lastTextNode = div.childNodes[div.childNodes.length - 1];
+ empty_first_text_range = document.createRange();
+ empty_first_text_range.setStart(firstTextNode,0);
+ empty_first_text_range.setEnd(firstTextNode,0);
+ empty_last_text_range = null;
+ if (firstTextNode != lastTextNode) {
+ empty_last_text_range = document.createRange();
+ empty_last_text_range.setStart(lastTextNode,0);
+ empty_last_text_range.setEnd(lastTextNode,0);
+ }
+ full_range = document.createRange();
+ full_range.setStart(div,0);
+ full_range.setEnd(div,div.childNodes.length);
+ return div;
+}
+
+function selEnd(div,child,index,split,s)
+{
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(start, index);
+ r.setEnd(div, div.childNodes.length);
+ if (!dry) start.splitText(split);
+ check(r,s,run+" selEnd "+child+","+index+","+split);
+}
+
+function selStart(div,child,index,split,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(div, 0);
+ r.setEnd(start, index);
+ if (!dry) start.splitText(split);
+ check(r,s,run+" selStart "+child+","+index+","+split);
+}
+
+function selMiddleStart(div,child,index,split,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(div, 1);
+ r.setEnd(start, index);
+ if (!dry) start.splitText(split);
+ check(r,s,run+" selMiddleStart "+child+","+index+","+split);
+}
+
+function selMiddleEnd(div,child,index,split,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(start, index);
+ r.setEnd(div, 2);
+ if (!dry) start.splitText(split);
+ check(r,s,run+" selMiddleEnd "+child+","+index+","+split);
+}
+
+function splitBefore(div,child,index,split,s)
+{
+ if (flush) document.body.getClientRects();
+ var start = div.childNodes[child];
+ var r = document.createRange();
+ sel.addRange(r);
+ r.setStart(div, 1);
+ r.setEnd(start, index);
+ if (!dry) div.childNodes[0].splitText(split);
+ check(r,s,run+" splitBefore "+child+","+index+","+split);
+}
+
+function runTests(s)
+{
+ run = s+":";
+ selEnd(newDiv('111'), 0,0,0,'111');
+ selEnd(newDiv('111'), 0,0,1,'111');
+ selEnd(newDiv('111'), 0,0,3,'111');
+ selEnd(newDiv(''), 0,0,0,'');
+ selEnd(newDiv('111'), 0,1,0,'11');
+ selEnd(newDiv('111'), 0,2,1,'1');
+ selEnd(newDiv('111'), 0,1,3,'11');
+ selEnd(newDiv('111','222'), 0,1,0,'11222');
+ selEnd(newDiv('111','222'), 0,2,1,'1222');
+ selEnd(newDiv('111','222'), 0,1,3,'11222');
+ selEnd(newDiv('111','222'), 1,1,0,'22');
+ selEnd(newDiv('111','222'), 1,2,1,'2');
+ selEnd(newDiv('','222'), 1,1,1,'22');
+ selEnd(newDiv('','222'), 0,0,0,'222');
+ selEnd(newDiv('111',''), 0,1,0,'11');
+ selEnd(newDiv('111','222'), 1,1,3,'22');
+ selEnd(newDiv('111','222','333'), 1,1,0,'22333');
+ selEnd(newDiv('111','222','333'), 1,2,1,'2333');
+ selEnd(newDiv('111','222','333'), 1,1,3,'22333');
+ selEnd(newDiv('111','222',''), 1,1,3,'22');
+ selEnd(newDiv('111','','333'), 0,1,3,'11333');
+
+ selStart(newDiv('111'), 0,0,0,'');
+ selStart(newDiv('111'), 0,0,1,'');
+ selStart(newDiv('111'), 0,0,3,'');
+ selStart(newDiv('111'), 0,1,0,'1');
+ selStart(newDiv('111'), 0,2,1,'11');
+ selStart(newDiv('111'), 0,1,3,'1');
+ selStart(newDiv(''), 0,0,0,'');
+ selStart(newDiv('111','222'), 0,1,0,'1');
+ selStart(newDiv('111','222'), 0,2,1,'11');
+ selStart(newDiv('111','222'), 0,1,3,'1');
+ selStart(newDiv('111','222'), 1,1,0,'1112');
+ selStart(newDiv('111','222'), 1,2,1,'11122');
+ selStart(newDiv('111','222'), 1,1,3,'1112');
+ selStart(newDiv('','222'), 1,1,2,'2');
+ selStart(newDiv('','222'), 0,0,0,'');
+ selStart(newDiv('111',''), 1,0,0,'111');
+ selStart(newDiv('111','222','333'), 1,1,0,'1112');
+ selStart(newDiv('111','222','333'), 1,2,1,'11122');
+ selStart(newDiv('111','222','333'), 1,1,3,'1112');
+ selStart(newDiv('111','','333'), 1,0,0,'111');
+ selStart(newDiv('111','222',''), 1,1,3,'1112');
+
+ selMiddleStart(newDiv('111','222','333'), 1,1,0,'2');
+ selMiddleStart(newDiv('111','222','333'), 1,2,1,'22');
+ selMiddleStart(newDiv('111','222','333'), 1,1,3,'2');
+ selMiddleStart(newDiv('111','222','333'), 2,1,0,'2223');
+ selMiddleStart(newDiv('111','222','333'), 2,2,1,'22233');
+ selMiddleStart(newDiv('111','222','333'), 2,1,3,'2223');
+ selMiddleStart(newDiv('111','','333'), 2,1,2,'3');
+ selMiddleStart(newDiv('111','','333'), 1,0,0,'');
+
+ selMiddleEnd(newDiv('111','222','333'), 0,1,0,'11222');
+ selMiddleEnd(newDiv('111','222','333'), 0,2,1,'1222');
+ selMiddleEnd(newDiv('111','222','333'), 0,1,3,'11222');
+ selMiddleEnd(newDiv('111','222','333'), 1,1,0,'22');
+ selMiddleEnd(newDiv('111','222','333'), 1,2,1,'2');
+ selMiddleEnd(newDiv('111','222','333'), 1,1,3,'22');
+ selMiddleEnd(newDiv('111','','333'), 0,1,2,'11');
+ selMiddleEnd(newDiv('111','','333'), 0,1,3,'11');
+ selMiddleEnd(newDiv('111','','333'), 1,0,0,'');
+
+ splitBefore(newDiv('111','222','333'), 1,1,0,'2');
+ splitBefore(newDiv('111','222','333'), 1,2,1,'22');
+ splitBefore(newDiv('111','222','333'), 1,1,3,'2');
+ splitBefore(newDiv('111','222','333'), 2,1,0,'2223');
+ splitBefore(newDiv('111','222','333'), 2,2,1,'22233');
+ splitBefore(newDiv('111','222','333'), 2,1,3,'2223');
+ splitBefore(newDiv('','222','333'), 1,1,0,'2');
+ splitBefore(newDiv('','','333'), 1,0,0,'');
+ splitBefore(newDiv('','222',''), 2,0,0,'222');
+ splitBefore(newDiv('111','','333'), 2,1,2,'3');
+}
+
+function boom()
+{
+ runTests("dry run"); // this is to verify the result strings without splitText()
+ dry = false;
+ flush = false;
+ runTests("no flush");
+ flush = true;
+ runTests("flush");
+}
+
+boom();
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_timeout_clamp.html b/dom/base/test/test_timeout_clamp.html
new file mode 100644
index 0000000000..1f0496235e
--- /dev/null
+++ b/dom/base/test/test_timeout_clamp.html
@@ -0,0 +1,163 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1378586
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1378586</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=1378586">Mozilla Bug 1378586</a>
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+// We need to clear our nesting level periodically. We do this by firing
+// a postMessage() to get a runnable on the event loop without any setTimeout()
+// nesting.
+function clearNestingLevel() {
+ return new Promise(resolve => {
+ window.addEventListener('message', () => {
+ resolve();
+ }, {once: true});
+ postMessage('done', '*');
+ });
+}
+
+function delayByTimeoutChain(iterations) {
+ return new Promise(resolve => {
+ let count = 0;
+ function tick() {
+ count += 1;
+ if (count >= iterations) {
+ resolve();
+ return;
+ }
+ setTimeout(tick, 0);
+ }
+ setTimeout(tick, 0);
+ });
+}
+
+function delayByInterval(iterations) {
+ return new Promise(resolve => {
+ let count = 0;
+ function tick() {
+ count += 1;
+ if (count >= iterations) {
+ resolve();
+ return;
+ }
+ }
+ setInterval(tick, 0);
+ });
+}
+
+function testNestedIntervals() {
+ return new Promise(resolve => {
+ const runCount = 100;
+ let counter = 0;
+ let intervalId = 0;
+ let prevInitTime = performance.now();
+ let totalTime = 0;
+ function intervalCallback() {
+ let now = performance.now();
+ let delay = now - prevInitTime;
+ totalTime += delay;
+ prevInitTime = now;
+ clearInterval(intervalId);
+ if (++counter < runCount) {
+ intervalId = setInterval(intervalCallback, 0);
+ } else {
+ // Delays should be clamped to 4ms after the initial calls, but allow
+ // some fuzziness, so divide by 2.
+ let expectedTime = runCount * 4 / 2;
+ ok(totalTime > expectedTime, "Should not run callbacks too fast.");
+ resolve();
+ }
+ }
+
+ // Use the timeout value defined in the spec, 4ms.
+ SpecialPowers.pushPrefEnv({ 'set': [["dom.min_timeout_value", 4]]},
+ intervalCallback);
+ });
+}
+
+// Use a very long clamp delay to make it easier to measure the change
+// in automation. Some of our test servers are very slow and noisy.
+const clampDelayMS = 10000;
+
+// We expect that we will clamp on the 5th callback. This should
+// be the same for both setTimeout() chains and setInterval().
+const expectedClampIteration = 5;
+
+async function runTests() {
+ // Things like pushPrefEnv() can use setTimeout() internally which may give
+ // us a nesting level. Clear the nesting level to start so this doesn't
+ // confuse the test.
+ await clearNestingLevel();
+
+ // Verify a setTimeout() chain clamps correctly
+ let start = performance.now();
+ await delayByTimeoutChain(expectedClampIteration);
+ let stop = performance.now();
+ let delta = stop - start;
+
+ ok(delta >= clampDelayMS, "setTimeout() chain clamped: " + stop + " - " + start + " = " + delta);
+ ok(delta < (2*clampDelayMS), "setTimeout() chain did not clamp twice");
+
+ await clearNestingLevel();
+
+ // Verify setInterval() clamps correctly
+ start = performance.now();
+ await delayByInterval(expectedClampIteration);
+ stop = performance.now();
+ delta = stop - start;
+
+ ok(delta >= clampDelayMS, "setInterval() clamped: " + stop + " - " + start + " = " + delta);
+ ok(delta < (2*clampDelayMS), "setInterval() did not clamp twice");
+
+ await clearNestingLevel();
+
+ // Verify a setTimeout() chain will continue to clamp past the first
+ // expected iteration.
+ const expectedDelay = (1 + expectedClampIteration) * clampDelayMS;
+
+ start = performance.now();
+ await delayByTimeoutChain(2 * expectedClampIteration);
+ stop = performance.now();
+ delta = stop - start;
+
+ ok(delta >= expectedDelay, "setTimeout() chain continued to clamp: " + stop + " - " + start + " = " + delta);
+
+ await clearNestingLevel();
+
+ // Verify setInterval() will continue to clamp past the first expected
+ // iteration.
+ start = performance.now();
+ await delayByTimeoutChain(2 * expectedClampIteration);
+ stop = performance.now();
+ delta = stop - start;
+
+ ok(delta >= expectedDelay, "setInterval() continued to clamp: " + stop + " - " + start + " = " + delta);
+
+ await testNestedIntervals();
+
+ SimpleTest.finish();
+}
+
+// It appears that it's possible to get unlucky with time jittering and fail this test.
+// If start is jittered upwards, everything executes very quickly, and delta has
+// a very high midpoint, we may have taken between 10 and 10.002 seconds to execute; but
+// it will appear to be 9.998. Turn off jitter (and add logging) to test this.
+SpecialPowers.pushPrefEnv({ 'set': [
+ ["dom.min_timeout_value", clampDelayMS],
+ ["privacy.resistFingerprinting.reduceTimerPrecision.jitter", false],
+ ]}, runTests);
+</script>
+
+</body>
+</html>
diff --git a/dom/base/test/test_timer_flood.html b/dom/base/test/test_timer_flood.html
new file mode 100644
index 0000000000..afbc841b34
--- /dev/null
+++ b/dom/base/test/test_timer_flood.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test Behavior During Timer Flood</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();
+// This test takes a long time to run and it times out on Android debug as a result.
+SimpleTest.requestLongerTimeout(5);
+
+function onLoad() {
+ return new Promise(resolve => {
+ addEventListener('load', resolve, { once: true });
+ });
+}
+
+// Create a frame that executes a timer flood. The frame signals
+// that is ready once the flood has had a chance to warm up.
+function withFloodFrame() {
+ return new Promise(resolve => {
+ let frame = document.createElement('iframe');
+ addEventListener('message', function onMsg(evt) {
+ if (evt.data === 'STARTED') {
+ removeEventListener('message', onMsg);
+ resolve(frame);
+ }
+ });
+ frame.src = 'file_timer_flood.html';
+ document.body.appendChild(frame);
+ });
+}
+
+// Test that we can load documents during a timer flood.
+function testFrameLoad() {
+ return new Promise(resolve => {
+ let frame = document.createElement('iframe');
+ frame.addEventListener('load', _ => {
+ frame.remove();
+ resolve();
+ }, { once: true });
+ document.body.appendChild(frame);
+ });
+}
+
+// Test that we can perform network requests while a timer flood
+// is occuring.
+function testFetch(url) {
+ return fetch(url).then(response => {
+ return response.text();
+ });
+}
+
+// Test that we can run animations for 5 seconds while a timer
+// flood is occuring.
+function testRequestAnimationFrame() {
+ return new Promise(resolve => {
+ let remainingFrames = 5 * 60;
+ function nextFrame() {
+ remainingFrames -= 1;
+ if (remainingFrames > 0) {
+ requestAnimationFrame(nextFrame);
+ } else {
+ resolve();
+ }
+ };
+ requestAnimationFrame(nextFrame);
+ });
+}
+
+let floodFrame;
+
+onLoad().then(_ => {
+ // Start a timer flood in a frame.
+ return withFloodFrame();
+}).then(frame => {
+ floodFrame = frame;
+
+ // Next we are going to start a bunch of asynchronous work that we
+ // expect to complete in spite of the timer flood. The type of work
+ // is a bit arbitrary, but is chosen to reflect the kinds of things
+ // we would like the browser to be able to do even when pages are
+ // abusing timers. Feel free to add more types of work here, but
+ // think carefully before removing anything.
+ let tests = [];
+
+ // Verify we can perform a variety of work while the timer flood
+ // is running.
+ for (let i = 0; i < 20; ++i) {
+ tests.push(testFrameLoad());
+ tests.push(testFetch('file_timer_flood.html'));
+ }
+ // Verify that animations still work while the timer flood is running.
+ // Note that we do one long run of animations instead of parallel runs
+ // like the other activities because of the way requestAnimationFrame()
+ // is scheduled. Parallel animations would not result in any additional
+ // runnables be placed on the event queue.
+ tests.push(testRequestAnimationFrame());
+
+ // Wait for all tests to finish. If we do not handle the timer flood
+ // well then this will likely time out.
+ return Promise.all(tests);
+}).then(_ => {
+ ok(true, 'completed tests without timing out');
+ floodFrame.remove();
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_title.html b/dom/base/test/test_title.html
new file mode 100644
index 0000000000..7b7a3f9f09
--- /dev/null
+++ b/dom/base/test/test_title.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <title>Test for titles</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style type="text/css">
+ </style>
+</head>
+
+<body onload="runTests()">
+
+<p id="display"></p>
+<div style="display:none;">
+ <iframe id="html1" src="data:text/html,<html><head><title id='t'>Test</title></head></html>"></iframe>
+ <iframe id="html2" src="data:text/html,<html><head><title id='t'>Test</title><title>Foo</title></head></html>"></iframe>
+ <iframe id="html3" src="data:text/html,<html></html>"></iframe>
+ <iframe id="xhtml1" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'><body><title id='t'>Test</title></body></html>"></iframe>
+ <iframe id="xhtml2" src="data:text/xml,<title xmlns='http://www.w3.org/1999/xhtml'>Test</title>"></iframe>
+ <iframe id="xhtml3" src="data:text/xml,<title xmlns='http://www.w3.org/1999/xhtml'>Te<div>bogus</div>st</title>"></iframe>
+ <iframe id="xhtml4" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'/>"></iframe>
+ <iframe id="xhtml5" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'><head/></html>"></iframe>
+ <iframe id="xhtml6" src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'><head><style/></head></html>"></iframe>
+ <iframe id="svg1" src="data:text/xml,<svg xmlns='http://www.w3.org/2000/svg'><title id='t'>Test</title></svg>"></iframe>
+ <iframe id="svg2" src="data:text/xml,<svg xmlns='http://www.w3.org/2000/svg'><title id='t'>Test</title></svg>"></iframe>
+</div>
+<pre id="test">
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ function testStatic(id, expect, description) {
+ var myFrame = document.getElementById(id);
+ var wrappedDoc = SpecialPowers.wrap(myFrame).contentDocument;
+ is(wrappedDoc.title, expect, description);
+ }
+
+ testStatic("html1", "Test", "HTML <title>");
+ testStatic("html2", "Test", "choose the first HTML <title>");
+ testStatic("html3", "", "No title");
+ testStatic("xhtml1", "Test", "XHTML <title> in body");
+ testStatic("xhtml2", "Test", "XHTML <title> as root element");
+ testStatic("xhtml3", "Test", "XHTML <title> containing an element");
+ testStatic("svg1", "Test", "SVG <title>");
+
+ SimpleTest.finish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_toScreenRect.html b/dom/base/test/test_toScreenRect.html
new file mode 100644
index 0000000000..7a3656ac36
--- /dev/null
+++ b/dom/base/test/test_toScreenRect.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+window.open('file_toScreenRect.html');
+</script>
+</html>
diff --git a/dom/base/test/test_treewalker_nextsibling.xml b/dom/base/test/test_treewalker_nextsibling.xml
new file mode 100644
index 0000000000..e38852dba2
--- /dev/null
+++ b/dom/base/test/test_treewalker_nextsibling.xml
@@ -0,0 +1,96 @@
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css" ?>
+<root>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js" xmlns="http://www.w3.org/1999/xhtml"/>
+
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display"></p>
+ <div id="content" style="display: none;"></div>
+ <textarea id="test" style="height: 300px; max-width: 800px; overflow: scroll;"
+ rows="10" cols="160" readonly="readonly"/>
+ </body>
+
+<pre id="test" xmlns="http://www.w3.org/1999/xhtml">
+<script class="testbody" type="text/javascript" xmlns="http://www.w3.org/1999/xhtml">
+<![CDATA[
+var passedNodes = new WeakMap();
+function setPass(aNode) {
+ passedNodes.set(aNode, true);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+window.addEventListener("load", function() {
+ var walker = document.createTreeWalker(
+ document,
+ NodeFilter.SHOW_TEXT | NodeFilter.SHOW_DOCUMENT,
+ null
+ );
+ setPass(walker.firstChild());
+ while (walker.nextSibling()) {
+ setPass(walker.currentNode);
+ }
+
+/*
+From http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/traversal.html#Traversal-TreeWalker
+Omitting nodes from the logical view of a subtree can result in a structure that
+is substantially different from the same subtree in the complete, unfiltered
+document. Nodes that are siblings in the TreeWalker view may be children of
+different, widely separated nodes in the original view. For instance, consider a
+NodeFilter that skips all nodes except for Text nodes and the root node of a
+document. In the logical view that results, all text nodes will be siblings and
+appear as direct children of the root node, no matter how deeply nested the
+structure of the original document.
+*/
+
+ walker2 = document.createTreeWalker(document, NodeFilter.SHOW_TEXT, null);
+ while (walker2.nextNode()) {
+ var cNode = walker2.currentNode;
+ ok(passedNodes.get(cNode), "Every text node should appear: " + walker2.currentNode.nodeValue);
+ walker.currentNode = cNode;
+ var parent = walker.parentNode();
+ is(parent, document, "parent of text node should be document");
+
+ // Check nextSibling's previousSibling.
+ walker.currentNode = cNode;
+ if (walker.nextSibling()) {
+ is(cNode, walker.previousSibling(), "nextSibling.previousSibling should be consistent");
+ }
+
+ // Check previousSibling's nextSibling.
+ walker.currentNode = cNode;
+ if (walker.previousSibling()) {
+ is(cNode, walker.nextSibling(), "previousSibling.nextSibling should be consistent");
+ }
+ }
+ SimpleTest.finish();
+}, true);
+]]>
+</script>
+</pre>
+
+ <test>
+ zero
+ <one>
+ one-A
+ <two>
+ two-A
+ </two>
+ <two>
+ two-B
+ </two>
+ one-B
+ </one>
+ <one>
+ one-C
+ <two>
+ two-D
+ </two>
+ <two>
+ two-E
+ </two>
+ one-F
+ </one>
+ zero
+ </test>
+</root>
+
diff --git a/dom/base/test/test_urgent_start.html b/dom/base/test/test_urgent_start.html
new file mode 100644
index 0000000000..1dd13c20c2
--- /dev/null
+++ b/dom/base/test/test_urgent_start.html
@@ -0,0 +1,269 @@
+<!DOCTYPE HTML>
+<!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1348050
+ Test for fetch and xhr to guarantee we only mark channel as urgent-start when
+ it is triggered by user input events.
+
+ For { Fetch, SRC-*, XHR }, do the test as following:
+ Step 1: Verify them not mark the channel when there is no any input event.
+ Step 2: Verify them mark the channel there is a user input event.
+ Step 3: Verify them not mark the channel when there is a non input event.
+
+ In each steps, it shows that we only mark channel on direct triggering task.
+ We won't mark the channel for additional task(setTimeout) or
+ micro-task(promise).
+-->
+<html>
+<head>
+ <title>Test for urgent-start on Fetch and XHR</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet"
+ type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<img id="image"></body>
+<audio autoplay id="audio"></audio>
+<iframe id="iframe"></iframe>
+<input type="image" id="input"></input>
+<embed id="embed"></embed>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTest);
+
+const topic_request = "http-on-opening-request";
+const topic_response = "http-on-examine-response";
+const topic_cachedResponse = "http-on-examine-cached-response";
+const scope = "http://mochi.test:8888/chrome/dom/base/test/"
+const url = scope + "file_empty.html";
+
+let expectedResults = [];
+let testcases = [
+ "fetch",
+ "src-embed",
+ "src-img",
+ "src-input",
+ "src-media",
+ "xhr",
+];
+let testcase;
+
+function isUrgentStart(aClassFlags) {
+ if (!aClassFlags) {
+ return false;
+ }
+
+ const urgentStartFlag = 1 << 6;
+ return !!(urgentStartFlag & aClassFlags);
+}
+
+// Test for setTimeout (task)
+function testSetTimeout() {
+ return new Promise(aResolve =>
+ setTimeout(function() {
+ testSimple().then(aResolve);
+ }, 0));
+}
+
+// Test for promise chain (micro-task)
+function testPromise() {
+ return Promise.resolve().then(testSimple);
+}
+
+function testSimple() {
+ let testUrl = url + "?" + expectedResults.length;
+
+ if (testcase == "fetch") {
+ return fetch(testUrl);
+ } else if (testcase == "src-embed") {
+ document.getElementById('embed').src = testUrl;
+ return Promise.resolve();
+ } else if (testcase == "src-img") {
+ document.getElementById('image').src = testUrl;
+ return Promise.resolve();
+ } else if (testcase == "src-input") {
+ document.getElementById('input').src = testUrl;
+ return Promise.resolve();
+ } else if (testcase == "src-media") {
+ document.getElementById('audio').src = testUrl;
+ return Promise.resolve();
+ } else if (testcase == "xhr") {
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", testUrl, true);
+ xhr.send(null);
+ return Promise.resolve();
+ }
+
+ ok(false, "Shouldn't go here.");
+}
+
+function sendRequsetAndCheckUrgentStart(aEventToTest) {
+ info("SendRequsetAndCheckUrgentStart");
+
+ let promise1, promise2;
+ let promise1_resolve, promise2_resolve;
+
+ function checkUrgentStart(aSubject) {
+ var channel = aSubject.QueryInterface(Ci.nsIChannel);
+ if (!channel.URI.spec.includes(scope) ) {
+ return;
+ }
+
+ info("CheckUrgentStart");
+
+ let cos = channel.QueryInterface(Ci.nsIClassOfService);
+
+ let expectedResult = expectedResults.shift();
+ is(isUrgentStart(cos.classFlags), expectedResult,
+ "Expect get: " + expectedResult + ", get: " +
+ isUrgentStart(cos.classFlags) + " in the " +
+ (9 - expectedResults.length) + " test of " + testcase);
+
+ // Make sure we've run the check.
+ promise1_resolve();
+ }
+
+ // Resolve this after we've gotten response to prevent from sending too many
+ // requests to Necko in a short time.
+ function getResponse(aSubject) {
+ var channel = aSubject.QueryInterface(Ci.nsIChannel);
+ if (!channel.URI.spec.includes(scope) ) {
+ return;
+ }
+ info("GetResponse");
+
+ promise2_resolve();
+ }
+
+ SpecialPowers.addObserver(checkUrgentStart, topic_request);
+ SpecialPowers.addObserver(getResponse, topic_response);
+ SpecialPowers.addObserver(getResponse, topic_cachedResponse);
+
+ return Promise.resolve()
+ .then(() => {
+ promise1 = new Promise(aResolve => { promise1_resolve = aResolve; });
+ promise2 = new Promise(aResolve => { promise2_resolve = aResolve; });
+ return Promise.all([addListenerAndSendEvent(testSimple, aEventToTest),
+ promise1,
+ promise2]);
+ })
+ .then(() => {
+ promise1 = new Promise(aResolve => { promise1_resolve = aResolve; });
+ promise2 = new Promise(aResolve => { promise2_resolve = aResolve; });
+ return Promise.all([addListenerAndSendEvent(testSetTimeout, aEventToTest),
+ promise1,
+ promise2]);
+ })
+ .then(() => {
+ promise1 = new Promise(aResolve => { promise1_resolve = aResolve; });
+ promise2 = new Promise(aResolve => { promise2_resolve = aResolve; });
+ return Promise.all([addListenerAndSendEvent(testPromise, aEventToTest),
+ promise1,
+ promise2]);
+ })
+ .then(() => {
+ // remove obs if we've tested each three conditions
+ // (simple, promise, setTimeout).
+ SpecialPowers.removeObserver(checkUrgentStart, topic_request);
+ SpecialPowers.removeObserver(getResponse,topic_response);
+ SpecialPowers.removeObserver(getResponse, topic_cachedResponse);
+ return Promise.resolve();
+ });
+}
+
+function addListenerAndSendEvent(aFunction, aEventToTest) {
+ info("AddListenerAndSendEvent:" + aEventToTest);
+
+ let eventHandle = function () {
+ return aFunction();
+ };
+
+ if (aEventToTest === TestEvent.USER_INPUT_EVENT) {
+ // User Input Event
+ window.addEventListener("mousedown", eventHandle, {once: true});
+ } else if (aEventToTest === TestEvent.NONUSER_INPUT_EVENT) {
+ window.addEventListener("message", eventHandle, {once: true});
+ }
+
+ if (aEventToTest === TestEvent.USER_INPUT_EVENT) {
+ // User Input Event
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
+ } else if (aEventToTest === TestEvent.NONUSER_INPUT_EVENT) {
+ window.postMessage("hello", "*");
+ } else if (aEventToTest === TestEvent.NOEVENT) {
+ eventHandle();
+ }
+}
+
+const TestEvent = {
+ NOEVENT: 0,
+ USER_INPUT_EVENT: 1,
+ NONUSER_INPUT_EVENT: 2,
+};
+
+function executeTest() {
+ is(expectedResults.length, 0, "expectedResults should be 0 be executeTest.");
+
+ // We will test fetch first and then xhr.
+ testcase = testcases.shift();
+ info("Verify " + testcase);
+
+ expectedResults = [
+ /* SimpleTest without any events */ false,
+ /* PromiseTest without any events */ false,
+ /* SetTimeoutTest without any events */ false,
+ /* SimpleTest with a user input event */ true,
+ /* PromiseTest with a user input event */ false,
+ /* SetTimeoutTest with user input event */ false,
+ /* SimpleTest with a non user input event */ false,
+ /* PromiseTest with a non user input event */ false,
+ /* SetTimeoutTest with a non user input event */ false,
+ ];
+
+ return Promise.resolve()
+ // Verify urgent-start is not set when the request is not triggered by any
+ // events.
+ .then(() => sendRequsetAndCheckUrgentStart(TestEvent.NOEVENT))
+
+ // Verify urgent-start is set only when the request is triggered by a user
+ // input event. (not for another microtask (e.g. promise-chain) and
+ // task (e.g. setTimeout)).
+ .then(() => sendRequsetAndCheckUrgentStart(TestEvent.USER_INPUT_EVENT))
+
+ // Verify urgent-start is not set when the request is triggered by a non user
+ // input event.
+ .then(() => sendRequsetAndCheckUrgentStart(TestEvent.NONUSER_INPUT_EVENT))
+ .then(_ => {
+ if (testcases.length !== 0) {
+ // Run the other test if we still have tests needed to be run.
+ return executeTest();
+ }
+
+ return Promise.resolve();
+ });
+}
+
+function endCheck() {
+ info("End Check: make sure that we've done all the tests.");
+
+ is(testcases.length, 0, "All the tests should be executed.");
+ is(expectedResults.length, 0, "All the tests should be executed.");
+
+ return Promise.resolve();
+}
+
+function runTest() {
+ return SpecialPowers.pushPrefEnv({"set": [["network.http.rcwn.enabled", false]]})
+ .then(executeTest)
+ .then(endCheck)
+ .catch(aError => ok(false, "Some test failed with error " + aError))
+ .then(SimpleTest.finish);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_user_select.html b/dom/base/test/test_user_select.html
new file mode 100644
index 0000000000..343772fbf7
--- /dev/null
+++ b/dom/base/test/test_user_select.html
@@ -0,0 +1,357 @@
+<!DOCTYPE>
+<html>
+<head>
+<title>user-select selection tests</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">
+@font-face {
+ font-family: Ahem;
+ src: url("Ahem.ttf");
+}
+body { font-family: Ahem; font-size: 20px; }
+s, .non-selectable { user-select: none; }
+n { display: none; }
+a { position:absolute; bottom: 0; right:0; }
+.text { user-select: text; }
+</style>
+
+</head>
+<body>
+
+<div id="test1">aaaaaaa<s>bbbbbbbb</s>ccccccc</div>
+<div id="test2"><s>aaaaaaa</s>bbbbbbbbccccccc</div>
+<div id="test3">aaaaaaabbbbbbbb<s>ccccccc</s></div>
+<div id="test4">aaaaaaa<x><s>bbbbbbbb</s></x>ccccccc</div>
+<div id="test5"><x><s>aaaaaaa</s></x>bbbbbbbbccccccc</div>
+<div id="test6">aaaaaaabbbbbbbb<x><s>ccccccc</s></x></div>
+<div id="test7">aaaaaaa<x><s><n>bbbb</n>bbbb</s></x>ccccccc</div>
+<div id="test8"><x><s>aa<n>aaa</n>aa</s></x>bbbbbbbbccccccc</div>
+<div id="test9">aaaaaaabbbbbbbb<x><s>cc<n>ccccc</n></s></x></div>
+<div id="testA">aaaaaaa<n>bbb<s>bbbbb</s></n>ccccccc</div>
+<div id="testB"><n><s>aaaa</s>aaa</n>bbbbbbbbccccccc</div>
+<div id="testC">aaaaaaabbbbbbbb<n>cc<s>c</s>cccc</n></div>
+<div id="testE">aaa<s id="testEc1">aaaa<a class="text">bbbb</a>dd<a>cccc</a>ddddddd</s>eeee</div>
+<div id="testI">aaa<span contenteditable="true" spellcheck="false">bbb</span><s>ccc</s>ddd</div>
+<div id="testF">aaaa
+<div class="non-selectable">x</div>
+<div class="non-selectable">x</div>
+<div class="non-selectable">x</div>
+bbbb</div>
+<div id="testG" style="white-space:pre">aaaa
+<div class="non-selectable">x</div>
+<div class="non-selectable">x</div>
+<div class="non-selectable">x</div>
+bbbb</div>
+<div id="testH" style="white-space:pre">aaaa
+<div class="non-selectable">x</div><input>
+bbbbbbb</div>
+
+<iframe id="testD" srcdoc="<body>aaaa<span style='user-select:none'>bbbb</span>cccc"></iframe>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function test()
+{
+ function clear(w)
+ {
+ var sel = (w ? w : window).getSelection();
+ sel.removeAllRanges();
+ }
+ function doneTest(e)
+ {
+ // We hide the elements we're done with so that later tests
+ // are inside the rather narrow iframe mochitest gives us.
+ // It matters for synthesizeMouse event tests.
+ e.style.display = 'none';
+ e.offsetHeight;
+ }
+
+ function dragSelect(e, x1, x2, x3)
+ {
+ dir = x2 > x1 ? 1 : -1;
+ synthesizeMouse(e, x1, 5, { type: "mousedown" });
+ synthesizeMouse(e, x1 + dir, 5, { type: "mousemove" });
+ if (x3)
+ synthesizeMouse(e, x3, 5, { type: "mousemove" });
+ synthesizeMouse(e, x2 - dir, 5, { type: "mousemove" });
+ synthesizeMouse(e, x2, 5, { type: "mouseup" });
+ }
+
+ function shiftClick(e, x)
+ {
+ synthesizeMouse(e, x, 5, { type: "mousedown", shiftKey: true });
+ synthesizeMouse(e, x, 5, { type: "mouseup", shiftKey: true });
+ }
+
+ function init(arr, e)
+ {
+ clear();
+ var sel = window.getSelection();
+ for (i = 0; i < arr.length; ++i) {
+ var data = arr[i];
+ var r = new Range()
+ r.setStart(node(e, data[0]), data[1]);
+ r.setEnd(node(e, data[2]), data[3]);
+ sel.addRange(r);
+ }
+ }
+
+ function NL(s) { return s.replace(/(\r\n|\n\r|\r)/g, '\n'); }
+
+ function checkText(text, e)
+ {
+ var sel = window.getSelection();
+ is(NL(sel.toString()), text, e.id + ": selected text")
+ }
+
+ function checkRangeText(text, index)
+ {
+ var r = window.getSelection().getRangeAt(index);
+ is(NL(r.toString()), text, e.id + ": range["+index+"].toString()")
+ }
+
+ function node(e, arg)
+ {
+ if (typeof arg == "number")
+ return arg == -1 ? e : e.childNodes[arg];
+ return arg;
+ }
+
+ function checkRangeCount(n, e)
+ {
+ var sel = window.getSelection();
+ is(sel.rangeCount, n, e.id + ": Selection range count");
+ }
+
+ function checkRange(i, expected, e) {
+ var sel = window.getSelection();
+ var r = sel.getRangeAt(i);
+ is(r.startContainer, node(e, expected[0]), e.id + ": range["+i+"].startContainer");
+ is(r.startOffset, expected[1], e.id + ": range["+i+"].startOffset");
+ is(r.endContainer, node(e, expected[2]), e.id + ": range["+i+"].endContainer");
+ is(r.endOffset, expected[3], e.id + ": range["+i+"].endOffset");
+ }
+
+ function checkRanges(arr, e)
+ {
+ checkRangeCount(arr.length, e);
+ for (i = 0; i < arr.length; ++i) {
+ var expected = arr[i];
+ checkRange(i, expected, e);
+ }
+ }
+
+ // ======================================================
+ // ================== dragSelect tests ==================
+ // ======================================================
+
+ var e = document.getElementById('test1');
+ dragSelect(e, 20, 340);
+ checkText('aaaaaacc', e);
+ checkRanges([[0,1,-1,1], [2,0,2,2]], e);
+
+ clear();
+ dragSelect(e, 20, 260, 120);
+ checkText('aaaaa', e);
+ checkRanges([[0,1,0,6]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('test2');
+ dragSelect(e, 20, 340);
+ checkText('', e);
+ checkRanges([], e);
+
+ clear();
+ dragSelect(e, 340, 20, 141);
+ checkText('bbbbbbbbcc', e);
+ checkRanges([[1,0,1,10]], e);
+ // #test2 is used again below
+
+ clear();
+ e = document.getElementById('test3');
+ dragSelect(e, 20, 340, 295);
+ checkText('aaaaaabbbbbbbb', e);
+ checkRanges([[0,1,0,15]], e);
+ // #test3 is used again below
+
+ clear();
+ e = document.getElementById('test4');
+ dragSelect(e, 20, 340);
+ checkText('aaaaaacc', e);
+ checkRanges([[0,1,1,0], [2,0,2,2]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('test5');
+ dragSelect(e, 340, 20, 141);
+ checkText('bbbbbbbbcc', e);
+ checkRanges([[1,0,1,10]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('test6');
+ dragSelect(e, 20, 340, 295);
+ checkText('aaaaaabbbbbbbb', e);
+ checkRanges([[0,1,0,15]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('test7');
+ dragSelect(e, 20, 340);
+ checkText('aaaaaacccccc', e);
+ checkRanges([[0,1,1,0], [2,0,2,6]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('test8');
+ dragSelect(e, 340, 20, 140);
+ checkText('bbbbbccccc', e);
+ checkRanges([[1,3,1,13]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('test9');
+ dragSelect(e, 20, 340, 295);
+ checkText('aaaaaabbbbbbbb', e);
+ checkRanges([[0,1,0,15]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('testA');
+ dragSelect(e, 20, 340);
+ checkText('aaaaaaccccccc', e);
+ checkRanges([[0,1,2,7]], e);
+ checkRangeText('aaaaaabbbbbbbbccccccc', 0);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('testB');
+ dragSelect(e, 340, 20, 140);
+ checkText('bbbbbbbccccccc', e);
+ checkRanges([[1,1,1,15]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('testE');
+ dragSelect(e, 20, 360, 295);
+ checkText('aa\nbbbb\nee', e);
+ checkRangeCount(3, e);
+ checkRange(0, [0,1,-1,1], e);
+ checkRange(1, [1,0,-1,2], e.children[0]);
+ checkRange(2, [2,0,2,2], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('testI');
+ dragSelect(e, 200, 80);
+ checkText('bbd', e);
+ checkRangeCount(2, e);
+ doneTest(e);
+
+ // ======================================================
+ // ================== shift+click tests =================
+ // ======================================================
+
+ // test extending a selection that starts in a -moz-user-select:none node
+ clear();
+ e = document.getElementById('test2');
+ init([[0,0,0,1]], e);
+ checkRangeText('aaaaaaa', 0);
+ checkText('', e);
+ shiftClick(e, 340);
+ checkRangeText('bbbbbbbbcc', 0);
+ checkText('bbbbbbbbcc', e);
+ checkRanges([[-1,1,1,10]], e);
+ doneTest(e);
+
+ // test extending a selection that end in a -moz-user-select:none node
+ clear();
+ e = document.getElementById('test3');
+ init([[1,0,1,1]], e);
+ checkRangeText('ccccccc', 0);
+ checkText('', e);
+ shiftClick(e, 20);
+ checkRangeText('aaaaaabbbbbbbb', 0);
+ checkText('aaaaaabbbbbbbb', e);
+ checkRanges([[0,1,-1,1]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('testF');
+ synthesizeMouse(e, 1, 1, {});
+ synthesizeMouse(e, 400, 100, { shiftKey: true });
+ checkText("aaaa bbbb", e);
+ checkRanges([[0,0,-1,1],[6,0,6,5]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('testG');
+ synthesizeMouse(e, 1, 1, {});
+ synthesizeMouse(e, 400, 180, { shiftKey: true });
+ checkText("aaaa\n\n\n\nbbbb", e);
+ checkRanges([[0,0,-1,1],[2,0,-1,3],[4,0,-1,5],[6,0,6,5]], e);
+ doneTest(e);
+
+ clear();
+ e = document.getElementById('testH');
+ synthesizeMouse(e, 1, 1, {});
+ synthesizeMouse(e, 30, 90, { shiftKey: true });
+ synthesizeMouse(e, 50, 90, { shiftKey: true });
+ synthesizeMouse(e, 70, 90, { shiftKey: true });
+ checkText("aaaa\n\nbbb", e);
+ checkRanges([[0,0,-1,1],[-1,2,3,4]], e);
+
+ doneTest(e);
+ // ======================================================
+ // ==================== Script tests ====================
+ // ======================================================
+
+ clear();
+ e = document.getElementById('testD');
+ clear(e.contentWindow);
+ sel = e.contentWindow.getSelection();
+ sel.selectAllChildren(e.contentDocument.body);
+ is(window.getSelection().rangeCount, 0, "testD: no selection in outer window");
+ is(sel.toString(), 'aaaacccc', "testD: scripted selection");
+ is(sel.rangeCount, 1, "testD: scripted selection isn't filtered");
+ is(sel.getRangeAt(0).toString(), 'aaaabbbbcccc', "testD: scripted selection isn't filtered");
+
+ // ======================================================
+ // ================== Kbd command tests =================
+ // ======================================================
+
+ clear();
+ e = document.getElementById('testD');
+ clear(e.contentWindow);
+ e.contentWindow.focus();
+ synthesizeKey("a", { accelKey:true }, e.contentWindow);
+ sel = e.contentWindow.getSelection();
+ is(window.getSelection().rangeCount, 0, "testD: no selection in outer window");
+ is(sel.toString(), 'aaaacccc', "testD: kbd selection");
+ is(sel.rangeCount, 2, "testD: kbd selection is filtered");
+ is(sel.getRangeAt(0).toString(), 'aaaa', "testD: kbd selection is filtered");
+ is(sel.getRangeAt(1).toString(), 'cccc', "testD: kbd selection is filtered");
+ doneTest(e);
+
+ clear();
+ SimpleTest.finish();
+}
+
+// These tests depends on the Ahem font being loaded and rendered so wait for
+// font to load, then wait a frame for them to be rendered too.
+window.onload = function() {
+ document.fonts.ready.then(function() {
+ requestAnimationFrame(test);
+ });
+};
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_viewport_metrics_on_landscape_content.html b/dom/base/test/test_viewport_metrics_on_landscape_content.html
new file mode 100644
index 0000000000..ec3cfec473
--- /dev/null
+++ b/dom/base/test/test_viewport_metrics_on_landscape_content.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script>
+'use strict';
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.meta-viewport.enabled", true],
+ ]
+}, () => {
+ // We need to open a new window to avoid running tests in an iframe since
+ // we want to test metrics on the root document.
+ window.open("file_viewport_metrics_on_landscape_content.html");
+});
+</script>
diff --git a/dom/base/test/test_viewport_scroll.html b/dom/base/test/test_viewport_scroll.html
new file mode 100644
index 0000000000..90c2e85355
--- /dev/null
+++ b/dom/base/test/test_viewport_scroll.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for mapping of scrollTop/scrollLeft to viewport</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="doTest()">
+<p id="display"></p>
+
+<iframe id="quirks"></iframe>
+<iframe id="standards"></iframe>
+<iframe id="xml"></iframe>
+
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var quirks = document.getElementById("quirks");
+var standards = document.getElementById("standards");
+var xml = document.getElementById("xml");
+
+quirks.src = "file_viewport_scroll_quirks.html";
+standards.srcdoc = "<!DOCTYPE HTML><html><body style='height:2000px; width:2000px;'>";
+xml.src = "file_viewport_scroll_xml.xml";
+
+function subtest(winProp, elemProp, win, correctElement, elemToSet, otherElem1, otherElem2) {
+ win.scrollTo(50, 50);
+ elemToSet[elemProp] = 100;
+ if (elemToSet == correctElement) {
+ is(Math.round(win[winProp]), 100, "Setting " + elemToSet.name + "." + elemProp + " should scroll");
+ is(elemToSet[elemProp], 100, "Reading back " + elemToSet.name + "." + elemProp + " after scrolling");
+ } else {
+ is(Math.round(win[winProp]), 50, "Setting " + elemToSet.name + "." + elemProp + " should not scroll");
+ is(elemToSet[elemProp], 0, "Reading back " + elemToSet.name + "." + elemProp + " after not scrolling");
+ }
+ if (otherElem1 == correctElement) {
+ is(otherElem1[elemProp], 50, "Reading back " + otherElem1.name + "." + elemProp + " (correct element) after not scrolling");
+ } else {
+ is(otherElem1[elemProp], 0, "Reading back " + otherElem1.name + "." + elemProp + " (irrelevant element)");
+ }
+ if (otherElem2 == correctElement) {
+ is(otherElem2[elemProp], 50, "Reading back " + otherElem2.name + "." + elemProp + " (correct element) after not scrolling");
+ } else {
+ is(otherElem2[elemProp], 0, "Reading back " + otherElem2.name + "." + elemProp + " (irrelevant element)");
+ }
+}
+
+function testScroll(winProp, elemProp, win, elemToSet, otherElem1, otherElem2) {
+ subtest(winProp, elemProp, win, elemToSet, elemToSet, otherElem1, otherElem2);
+ subtest(winProp, elemProp, win, elemToSet, otherElem1, elemToSet, otherElem2);
+ subtest(winProp, elemProp, win, elemToSet, otherElem2, elemToSet, otherElem1);
+}
+
+function doTest() {
+ var quirksRoot = quirks.contentDocument.documentElement;
+ quirksRoot.name = "quirks HTML";
+ var quirksBody = quirks.contentDocument.body;
+ quirksBody.name = "quirks BODY";
+ var quirksBody2 = quirks.contentDocument.createElement("body");
+ quirksBody2.name = "quirks other BODY";
+ quirksRoot.appendChild(quirksBody2);
+ testScroll("scrollX", "scrollLeft", quirks.contentWindow, quirksBody, quirksRoot, quirksBody2);
+ testScroll("scrollY", "scrollTop", quirks.contentWindow, quirksBody, quirksRoot, quirksBody2);
+
+ var standardsRoot = standards.contentDocument.documentElement;
+ standardsRoot.name = "standards HTML";
+ var standardsBody = standards.contentDocument.body;
+ standardsBody.name = "standards BODY";
+ var standardsBody2 = standards.contentDocument.createElement("body");
+ standardsBody2.name = "standards other BODY";
+ standardsRoot.appendChild(standardsBody2);
+ testScroll("scrollX", "scrollLeft", standards.contentWindow, standardsRoot, standardsBody, standardsBody2);
+ testScroll("scrollY", "scrollTop", standards.contentWindow, standardsRoot, standardsBody, standardsBody2);
+
+ var xmlRoot = xml.contentDocument.documentElement;
+ xmlRoot.name = "XML root";
+ var xmlOther = xmlRoot.firstChild;
+ xmlOther.name = "XML other";
+ testScroll("scrollX", "scrollLeft", xml.contentWindow, xmlRoot, xmlOther, xmlOther);
+ testScroll("scrollY", "scrollTop", xml.contentWindow, xmlRoot, xmlOther, xmlOther);
+
+ SimpleTest.finish();
+}
+</script>
+
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_viewsource_forbidden_in_object.html b/dom/base/test/test_viewsource_forbidden_in_object.html
new file mode 100644
index 0000000000..ee48b2f051
--- /dev/null
+++ b/dom/base/test/test_viewsource_forbidden_in_object.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=973837
+-->
+<head>
+<meta charset="utf-8">
+<title>Tests for Bug 973837</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script>
+ SimpleTest.waitForExplicitFinish();
+
+ const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+
+ function runObjectURITest(testCase) {
+ var testObject = document.getElementById("testObject");
+ testObject.data = testCase.URI;
+
+ testObject instanceof OBJLC;
+ testObject = SpecialPowers.wrap(testObject);
+
+ is(testObject.displayedType, OBJLC.TYPE_NULL, testCase.desc +
+ " testObject.displayedType should be TYPE_NULL (4)");
+ runNextTest();
+ }
+
+ var testCaseIndex = -1;
+ testCases = [
+ {
+ desc: "Test 1: view-source should not be allowed in an object.",
+ URI: "view-source:file_general_document.html"
+ },
+ {
+ desc: "Test 2: jar:view-source should not be allowed in an object",
+ URI: "jar:view-source:file_general_document.html/!/"
+ },
+ ];
+
+ function runNextTest() {
+ ++testCaseIndex;
+ if (testCaseIndex == testCases.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ runObjectURITest(testCases[testCaseIndex]);
+ }
+
+ addLoadEvent(runNextTest);
+</script>
+</head>
+
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=973837">Mozilla Bug 973837</a>
+<p id="display"></p>
+
+<object id="testObject"></object>
+
+</body>
+</html>
diff --git a/dom/base/test/test_w3element_traversal.html b/dom/base/test/test_w3element_traversal.html
new file mode 100644
index 0000000000..efbcc41a89
--- /dev/null
+++ b/dom/base/test/test_w3element_traversal.html
@@ -0,0 +1,148 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>W3 Tests for Element Traversal - HTML</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+ <p id="parentEl_count">
+ <span id="first_element_child_count">
+ <span></span>
+ <span></span>
+ </span>
+ <span id="middle_element_child_count"></span>
+ <span id="last_element_child_count"></span>
+ </p>
+
+
+ <p id="parentEl_nochild">
+ </p>
+
+ <p id="parentEl_null">
+ </p>
+
+ <p id="parentEl_dynamicadd">
+ <span id="first_emement_child_add"></span>
+ </p>
+
+ <p id="parentEl_dynamicremove">
+ <span id="first_emement_child_remove"></span>
+ <span id="last_emement_child_remove"></span>
+ </p>
+
+
+ <p id="parentEl_fec">
+ <span id="first_element_child_fec"></span>
+ </p>
+
+ <p id="parentEl_lec">
+ <span id="first_element_child_lec"></span>
+ <span id="last_element_child_lec"></span>
+ </p>
+
+ <p id="parentEl_namespace">
+ <pickle:span id="first_element_child_namespace"></pickle:span>
+ </p>
+
+ <p id="parentEl_nes">
+ <span id="first_element_child_nes"></span>
+ <span id="last_element_child_nes"></span>
+ </p>
+
+ <p id="parentEl_pes">
+ <span id="first_element_child_pes"></span>
+ <span id="middle_element_child_pes"></span>
+ <span id="last_element_child_pes"></span>
+ </p>
+
+ <p id="parentEl_sibnull">
+ <span id="first_element_child_sibnull"></span>
+ </p>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+
+
+function runTest() {
+
+ //from et-childElementCount.html
+ var parentEl = document.getElementById("parentEl_count");
+ is(parentEl.childElementCount && 3, parentEl.childElementCount, "Child Element Count is mismatched");
+
+ //from et-childElementCount-nochild.html
+ var parentEl_nochild = document.getElementById("parentEl_nochild");
+ is(parentEl_nochild.childElementCount, 0, "Child Element count is not 0");
+
+ //from et-childElementCount-null.html
+ parentEl = document.getElementById("parentEl_null");
+ is(null == parentEl.firstElementChild, null == parentEl.lastElementChild, "firstElementChild or lastElementChild is not null");
+
+ //from et-dynamic-add.html
+ parentEl = document.getElementById("parentEl_dynamicadd");
+ var newChild = document.createElement("span")
+ parentEl.appendChild( newChild );
+ is(parentEl.childElementCount && 2, parentEl.childElementCount, "failed to add span element");
+
+ //from et-dynamic-remove.html
+ parentEl = document.getElementById("parentEl_dynamicremove");
+ var lec = parentEl.lastElementChild;
+ parentEl.removeChild( lec );
+ is(parentEl.childElementCount && 1, parentEl.childElementCount, "failed to remove span element");
+
+ //from et-firstElementChild.html
+ parentEl = document.getElementById("parentEl_fec");
+ var fec = parentEl.firstElementChild;
+ is(fec.nodeType, 1, "failed to get firstElementChild");
+ is(fec.getAttribute("id"), "first_element_child_fec", "failed to get firstElementChild");
+ isnot(fec, null, "failed to get firstElementChild");
+
+ //from et-lastElementChild.html
+ parentEl = document.getElementById("parentEl_lec");
+ var lec = parentEl.lastElementChild;
+ is(lec.nodeType, 1, "failed to get lastElementChild");
+ is(lec.getAttribute("id"), "last_element_child_lec", "failed to get lastElementChild");
+ isnot(lec, null, "failed to get lastElementChild");
+
+ //from et-namespace.html
+ parentEl = document.getElementById("parentEl_namespace");
+ var fec = parentEl.firstElementChild;
+ isnot(fec, null, "failed to get firstElementChild in namespace");
+ is(fec.getAttribute("id"), "first_element_child_namespace", "failed to get firstElementChild in namespace");
+
+ //from et-nextElementSibling.html
+ parentEl = document.getElementById("parentEl_nes");
+ var fec = parentEl.firstElementChild;
+ var nes = fec.nextElementSibling;
+ is(nes.nodeType, 1, "failed to get nextElementSibling");
+ is(nes.getAttribute("id"), "last_element_child_nes", "failed to get nextElementSibling");
+ isnot(nes, null, "failed to get nextElementSibling");
+
+ //from et-previousElementSibling.html
+ var lec = document.getElementById("last_element_child_pes");
+ var pes = lec.previousElementSibling;
+ is(pes.nodeType, 1, "failed to get previousElementSibling");
+ is(pes.getAttribute("id"), "middle_element_child_pes", "failed to get previousElementSibling");
+ isnot(pes, null, "failed to get previousElementSibling");
+
+ //from et-siblingElement-null.html
+ var fec = document.getElementById("first_element_child_sibnull");
+ var pes = fec.previousElementSibling;
+ var nes = fec.nextElementSibling;
+ is(pes, null, "got unexpected previousElementSibling");
+ is(nes, null, "got unexpected nextElementSibling");
+
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+addLoadEvent(SimpleTest.finish)
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_w3element_traversal.xhtml b/dom/base/test/test_w3element_traversal.xhtml
new file mode 100644
index 0000000000..334d184304
--- /dev/null
+++ b/dom/base/test/test_w3element_traversal.xhtml
@@ -0,0 +1,149 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:pickle="http://ns.example.org/pickle" lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <title>W3 Tests for Element Traversal - XHTML</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+ <p id="parentEl_count">
+ <span id="first_element_child_count">
+ <span></span>
+ <span></span>
+ </span>
+ <span id="middle_element_child_count"></span>
+ <span id="last_element_child_count"></span>
+ </p>
+
+
+ <p id="parentEl_nochild">
+ </p>
+
+ <p id="parentEl_null">
+ </p>
+
+ <p id="parentEl_dynamicadd">
+ <span id="first_emement_child_add"></span>
+ </p>
+
+ <p id="parentEl_dynamicremove">
+ <span id="first_emement_child_remove"></span>
+ <span id="last_emement_child_remove"></span>
+ </p>
+
+
+ <p id="parentEl_fec">
+ <span id="first_element_child_fec"></span>
+ </p>
+
+ <p id="parentEl_lec">
+ <span id="first_element_child_lec"></span>
+ <span id="last_element_child_lec"></span>
+ </p>
+
+ <div id="parentEl_namespace">
+ <pickle:dill />
+ </div>
+
+ <p id="parentEl_nes">
+ <span id="first_element_child_nes"></span>
+ <span id="last_element_child_nes"></span>
+ </p>
+
+ <p id="parentEl_pes">
+ <span id="first_element_child_pes"></span>
+ <span id="middle_element_child_pes"></span>
+ <span id="last_element_child_pes"></span>
+ </p>
+
+ <p id="parentEl_sibnull">
+ <span id="first_element_child_sibnull"></span>
+ </p>
+
+<pre id="test">
+<script class="testbody" type="text/javascript"><![CDATA[
+
+
+
+function runTest() {
+
+ //from et-childElementCount.html
+ var parentEl = document.getElementById("parentEl_count");
+ is(parentEl.childElementCount && 3, parentEl.childElementCount, "Child Element Count is mismatched");
+
+ //from et-childElementCount-nochild.html
+ var parentEl_nochild = document.getElementById("parentEl_nochild");
+ is(parentEl_nochild.childElementCount, 0, "Child Element count is not 0");
+
+ //from et-childElementCount-null.html
+ parentEl = document.getElementById("parentEl_null");
+ is(null == parentEl.firstElementChild, null == parentEl.lastElementChild, "firstElementChild or lastElementChild is not null");
+
+ //from et-dynamic-add.html
+ parentEl = document.getElementById("parentEl_dynamicadd");
+ var newChild = document.createElement("span")
+ parentEl.appendChild( newChild );
+ is(parentEl.childElementCount && 2, parentEl.childElementCount, "failed to add span element");
+
+ //from et-dynamic-remove.html
+ parentEl = document.getElementById("parentEl_dynamicremove");
+ var lec = parentEl.lastElementChild;
+ parentEl.removeChild( lec );
+ is(parentEl.childElementCount && 1, parentEl.childElementCount, "failed to remove span element");
+
+ //from et-firstElementChild.html
+ parentEl = document.getElementById("parentEl_fec");
+ var fec = parentEl.firstElementChild;
+ is(fec.nodeType, 1, "failed to get firstElementChild");
+ is(fec.getAttribute("id"), "first_element_child_fec", "failed to get firstElementChild");
+ isnot(fec, null, "failed to get firstElementChild");
+
+ //from et-lastElementChild.html
+ parentEl = document.getElementById("parentEl_lec");
+ var lec = parentEl.lastElementChild;
+ is(lec.nodeType, 1, "failed to get lastElementChild");
+ is(lec.getAttribute("id"), "last_element_child_lec", "failed to get lastElementChild");
+ isnot(lec, null, "failed to get lastElementChild");
+
+ //from et-namespace.html
+ parentEl = document.getElementById("parentEl_namespace");
+ var nChild = parentEl.firstElementChild;
+ is(nChild && "dill", nChild.localName, "failed to get a namespace element");
+
+
+ //from et-nextElementSibling.html
+ parentEl = document.getElementById("parentEl_nes");
+ var fec = parentEl.firstElementChild;
+ var nes = fec.nextElementSibling;
+ is(nes.nodeType, 1, "failed to get nextElementSibling");
+ is(nes.getAttribute("id"), "last_element_child_nes", "failed to get nextElementSibling");
+ isnot(nes, null, "failed to get nextElementSibling");
+
+ //from et-previousElementSibling.html
+ var lec = document.getElementById("last_element_child_pes");
+ var pes = lec.previousElementSibling;
+ is(pes.nodeType, 1, "failed to get previousElementSibling");
+ is(pes.getAttribute("id"), "middle_element_child_pes", "failed to get previousElementSibling");
+ isnot(pes, null, "failed to get previousElementSibling");
+
+ //from et-siblingElement-null.html
+ var fec = document.getElementById("first_element_child_sibnull");
+ var pes = fec.previousElementSibling;
+ var nes = fec.nextElementSibling;
+ is(pes, null, "got unexpected previousElementSibling");
+ is(nes, null, "got unexpected nextElementSibling");
+
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(runTest);
+addLoadEvent(SimpleTest.finish)
+]]></script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_w3element_traversal_svg.html b/dom/base/test/test_w3element_traversal_svg.html
new file mode 100644
index 0000000000..596200b424
--- /dev/null
+++ b/dom/base/test/test_w3element_traversal_svg.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Test for ElementTraversal via SVG</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>
+
+<iframe id="svg" src="w3element_traversal.svg"></iframe>
+
+<pre id="test">
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function run()
+{
+ var doc = $("svg").contentDocument;
+
+ //et-namespace.svg
+ var parentEl = doc.getElementById("parentEl_namespace");
+ var nChild = parentEl.firstElementChild;
+ is(nChild && "dill", nChild.localName, "failed to get child with namespace")
+
+ //et-previousElementSibling.svg
+ var lec = doc.getElementById("last_element_child_pes");
+ var pes = lec.previousElementSibling;
+ isnot(pes, null, "previousElementSibling is null");
+ is(pes.nodeType, 1, "previousElementSibling returned the wrong node type");
+ is(pes.getAttribute("id"), "middle_element_child_pes", "previousElementSibling returned the wrong child");
+
+ //et-sibling_null.svg
+ var fec = doc.getElementById("first_element_child_sibnull");
+ var pes = fec.previousElementSibling;
+ var nes = fec.nextElementSibling;
+ is(pes, null, "previousElementSibling is not null");
+ is(nes, null, "nextElementSibling is not null");
+
+ //et-nextElementSibling.svg
+ fec = doc.getElementById("first_element_child_nes");
+ var nes = fec.nextElementSibling;
+ isnot(nes, null, "nextElementSibling returned NULL");
+ is(nes.nodeType, 1, "nextElementSibling returned wrong node type");
+ is(nes.getAttribute("id"), "last_element_child_nes", "nextElementSibling returned wrong node id");
+
+ //et-lastElementChild.svg
+ var parentEl = doc.getElementById("parentEl_lec");
+ var lec = parentEl.lastElementChild;
+ isnot(lec, null, "lastElementChild returned null");
+ is(lec.nodeType, 1, "lastElementChild returned wrong nodeType");
+ is(lec.getAttribute("id"), "last_element_child_lec", "lastElementChild returned wrong id");
+
+ //et-firstElementChild.svg
+ var parentEl = doc.getElementById("parentEl_fec");
+ var fec = parentEl.firstElementChild;
+ isnot(fec, null, "firstElementChild returned null");
+ is(fec.nodeType, 1, "firstElementChild returned wrong nodeType");
+ is(fec.getAttribute("id"), "first_element_child_fec", "firstElementChild returned wrong id");
+
+ //et-entity.svg
+ var parentEl = doc.getElementById("parentEl_entity");
+ var fec = parentEl.firstElementChild;
+ isnot(fec, null, "firstElementChild returned null");
+ is(fec.nodeType, 1, "firstElementChild returned wrong nodeType");
+ is(fec.getAttribute("id"), "first_element_child_entity", "firstElementChild returned wrong id");
+
+ //et-dynamic-remove.svg
+ var parentEl = doc.getElementById("parentEl_dynremove");
+ var lec = parentEl.lastElementChild;
+ parentEl.removeChild( lec );
+ is(parentEl.childElementCount && 1, parentEl.childElementCount, "failed to removeChild");
+
+ //et-dynamic-add.svg
+ var parentEl = doc.getElementById("parentEl_dynadd");
+ var newChild = doc.createElementNS("http://www.w3.org/2000/svg", "tspan");
+ parentEl.appendChild( newChild );
+ is(parentEl.childElementCount && 2, parentEl.childElementCount, "failed to appendChild");
+
+ //et-childElement-null.svg
+ var parentEl = doc.getElementById("parentEl_null");
+ var fec = parentEl.firstElementChild;
+ var lec = parentEl.lastElementChild;
+ is(fec, null, "expected null from firstElementChild");
+ is(lec, null, "expected null from lastElementChild");
+
+
+ //et-childElementCount.svg
+ var parentEl = doc.getElementById("parentEl_count");
+ is(parentEl.childElementCount && 3, parentEl.childElementCount, "got wrong childElementCount");
+
+ //et-childElementCount-nochild.svg
+ var parentEl = doc.getElementById("parentEl_nochild");
+ is(0, parentEl.childElementCount, "got wrong childElementCount");
+
+
+ SimpleTest.finish();
+}
+
+window.addEventListener("load", run);
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/base/test/test_warning_for_blocked_cross_site_request.html b/dom/base/test/test_warning_for_blocked_cross_site_request.html
new file mode 100644
index 0000000000..c1e597b6ad
--- /dev/null
+++ b/dom/base/test/test_warning_for_blocked_cross_site_request.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=713980
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 713980</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <!-- Load a cross-origin webfont without CORS (common pain point) and some
+ other styles that require anonymous CORS -->
+ <style>
+ @font-face {
+ font-family: "bad_cross_origin_webfont";
+ src: url('http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=font_bad&type=application/octet-stream');
+ }
+ div#bad_webfont { font-family: "bad_cross_origin_webfont"; }
+
+ div#bad_shape_outside { shape-outside: url('http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=bad_shape_outside&type=image/png'); }
+
+ div#bad_mask_image { mask-image: url('http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=bad_mask_image&type=image/svg+xml'); }
+ </style>
+</head>
+<body>
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var tests = {
+ xhr : {
+ uri_test : "http://invalid",
+ result : null,
+ category: "CORSAllowOriginNotMatchingOrigin"
+ },
+ font : {
+ uri_test : "font_bad",
+ result : null,
+ category: "CORSMissingAllowOrigin2",
+ },
+ shape_outside : {
+ uri_test : "bad_shape_outside",
+ result : null,
+ category: "CORSMissingAllowOrigin2",
+ ignore_windowID: true,
+ },
+ mask_image : {
+ uri_test : "bad_mask_image",
+ result : null,
+ category: "CORSMissingAllowOrigin2",
+ ignore_windowID: true,
+ },
+}
+
+function testsComplete() {
+ for (var testName in tests) {
+ var test = tests[testName];
+ if (test.result == null) {
+ info("Still waiting on (at least) " + testName + ".");
+ return false;
+ }
+ }
+ return true;
+}
+
+SpecialPowers.registerConsoleListener(function CORSMsgListener(aMsg) {
+ if (!/Cross-Origin Request Blocked/.test(aMsg.message))
+ return;
+
+ for (var testName in tests) {
+ var test = tests[testName];
+ var category = test.category;
+ if (test.result != null)
+ continue;
+
+ var testRegexp = new RegExp(test.uri_test);
+ if (testRegexp.test(aMsg.message)) {
+ test.result = true;
+ ok(true, "Got \"Cross-site request blocked\" warning message for " + testName);
+ ok(aMsg.category == category,
+ "Got warning message with category \"" + aMsg.category + "\", expected \"" + category + "\"");
+ // Got the message we wanted - make sure it is destined for a valid inner window
+ if(!test.ignore_windowID) {
+ ok(aMsg.windowID != 0, "Valid (non-zero) windowID for the cross-site request blocked message.");
+ }
+ break;
+ }
+ }
+
+ if (testsComplete()) {
+ SimpleTest.executeSoon(cleanup);
+ }
+});
+
+function cleanup() {
+ SpecialPowers.postConsoleSentinel();
+ SimpleTest.finish();
+}
+
+// Send a cross-origin XHR request without CORS
+var xhr = new XMLHttpRequest();
+xhr.open("GET", "http://example.org/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?allowOrigin=http://invalid", true);
+xhr.send(null);
+
+let badDiv;
+
+// Create a div that triggers a cross-origin webfont request
+// We do this in Javascript in order to guarantee the console listener has
+// already been registered; otherwise, there could be a race.
+badDiv = document.createElement('div');
+badDiv.setAttribute('id', 'bad_webfont');
+document.body.appendChild(badDiv);
+
+// Create a div that triggers a cross-origin request for a shape-outside image
+badDiv = document.createElement('div');
+badDiv.setAttribute('id', 'bad_shape_outside');
+document.body.appendChild(badDiv);
+
+// Create a div that triggers a cross-origin request for a mask-image
+badDiv = document.createElement('div');
+badDiv.setAttribute('id', 'bad_mask_image');
+document.body.appendChild(badDiv);
+</script>
+
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_close.html b/dom/base/test/test_window_close.html
new file mode 100644
index 0000000000..5b0d7e6fa6
--- /dev/null
+++ b/dom/base/test/test_window_close.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>test window.close()</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ var b = new BroadcastChannel("windowclose");
+
+ const link = "link";
+ const windowopen = "window.open()";
+ var tests = [
+ {
+ type: windowopen,
+ noopener: true,
+ shouldCloseWithoutHistory: true,
+ shouldCloseWithHistory: false
+ },
+ {
+ type: windowopen,
+ noopener: false,
+ shouldCloseWithoutHistory: true,
+ shouldCloseWithHistory: true
+ },
+ {
+ type: link,
+ noopener: true,
+ shouldCloseWithoutHistory: true,
+ shouldCloseWithHistory: false
+ },
+ {
+ type: link,
+ noopener: false,
+ shouldCloseWithoutHistory: true,
+ shouldCloseWithHistory: true
+ }
+ ];
+
+ var loadTypes = ["withouthistory", "withhistory"];
+
+ async function start() {
+ // If Fission is disabled, the pref is no-op.
+ await SpecialPowers.pushPrefEnv({set: [["fission.bfcacheInParent", true]]});
+
+ for (let test of tests) {
+ await SpecialPowers.pushPrefEnv({ set: [["dom.allow_scripts_to_close_windows", false]]});
+ if (test.type == windowopen) {
+ for (let loadType of loadTypes) {
+ var features = test.noopener ? "noopener" : "";
+ window.open("file_window_close.html?" + loadType, "", features);
+ await new Promise(function(r) {
+ b.onmessage = function(e) {
+ var expectedClose = loadType == "withouthistory" ?
+ test.shouldCloseWithoutHistory : test.shouldCloseWithHistory;
+ is(e.data, expectedClose ? "closed" : "blocked",
+ "Expected close on " + loadType + ": " + expectedClose);
+ r();
+ }
+ });
+ }
+ } else if (test.type == link) {
+ var rel = test.noopener ? "rel='noopener'" : "";
+ for (let loadType of loadTypes) {
+ document.getElementById("content").innerHTML =
+ "<a href='file_window_close.html?" + loadType + "'" +
+ " target='foo' " + rel + "'>link</a>";
+ var p = new Promise(function(r) {
+ b.onmessage = function(e) {
+ var expectedClose = loadType == "withouthistory" ?
+ test.shouldCloseWithoutHistory : test.shouldCloseWithHistory;
+ is(e.data, expectedClose ? "closed" : "blocked",
+ "Expected close on " + loadType + ": " + expectedClose);
+ r();
+ }
+ });
+ document.getElementById("content").firstChild.click();
+ await p;
+ }
+ }
+ }
+ SimpleTest.finish();
+ }
+
+ </script>
+</head>
+<body onload="setTimeout(start)">
+<p id="display"></p>
+<div id="content"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_constructor.html b/dom/base/test/test_window_constructor.html
new file mode 100644
index 0000000000..6e7058356d
--- /dev/null
+++ b/dom/base/test/test_window_constructor.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=824217
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 824217</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=622491">Mozilla Bug 824217</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe name="constructor" src="about:blank"></iframe>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function run()
+{
+ // Ideally we'd test that this property lives on the right place in the
+ // [[Prototype]] chain, with the right attributes there, but we don't
+ // implement this right yet, so just test the value's what's expected.
+ is(window.constructor, Window,
+ "should have gotten Window, not the constructor frame");
+ SimpleTest.finish();
+}
+
+window.addEventListener("load", run);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_content.html b/dom/base/test/test_window_content.html
new file mode 100644
index 0000000000..8ffc6ed03f
--- /dev/null
+++ b/dom/base/test/test_window_content.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1400139
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1400139</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 1400139 **/
+ var props = [];
+ for (var prop in window) props.push(prop);
+ is(props.indexOf("content"), -1, "Should not have a property named 'content'");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1400139">Mozilla Bug 1400139</a>
+<p id="display"></p>
+<div id="notcontent" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_cross_origin_props.html b/dom/base/test/test_window_cross_origin_props.html
new file mode 100644
index 0000000000..1f7600c6e0
--- /dev/null
+++ b/dom/base/test/test_window_cross_origin_props.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=946067
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 946067</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 946067 **/
+ SimpleTest.waitForExplicitFinish();
+
+ function doGet(prop, thisObj) {
+ return Object.getOwnPropertyDescriptor(window, prop).get.call(thisObj);
+ }
+
+ function doSet(prop, thisObj, value) {
+ return Object.getOwnPropertyDescriptor(window, prop).set.call(thisObj, value);
+ }
+
+ window.onload = function() {
+ frames[0].focus();
+ is(document.activeElement.id, "x", "Should have focused first subframe");
+ frames[0].blur();
+ window.focus.call(frames[1]);
+ is(document.activeElement.id, "y", "Should have focused second subframe");
+ window.blur.call(frames[1]);
+
+ frames[0].close();
+ is(frames[0].closed, false, "Subframe is not closed");
+ window.close.call(frames[0]);
+ is(doGet("closed", frames[0]), false, "Subframe is still not closed");
+
+ is(frames[0].frames, frames[0], "window.frames === window");
+ is(doGet("frames", frames[0]), frames[0],
+ "Really, window.frames === window");
+
+ try {
+ frames[0].frames = 1;
+ ok(false, "Should throw when setting .frames");
+ } catch (e) {
+ ok(true, "Should throw when setting .frames");
+ }
+ try {
+ doSet("frames", frames[0], 1);
+ ok(false, "Should still throw when setting .frames");
+ } catch (e) {
+ ok(true, "Should still throw when setting .frames");
+ }
+
+ // Just check whether we can get the location without throwing:
+ is(frames[0].location, doGet("location", frames[0]),
+ "Should be same Location object");
+
+ is(frames[0].length, 0, "404 page has no subframes");
+ is(doGet("length", frames[0]), 0, "404 page has no subframes");
+
+ is(frames[0].opener, null, "subframe has no opener");
+ is(doGet("opener", frames[0]), null, "subframe still has no opener");
+
+ is(frames[0].parent, window, "subframe has us as parent");
+ is(doGet("parent", frames[0]), window, "subframe still has us as parent");
+
+ // Check that postMessage doesn't throw
+ frames[0].postMessage(null, "*");
+
+ is(frames[0].self, frames[0], "self should work");
+ is(doGet("self", frames[0]), frames[0], "self should still work");
+
+ is(frames[0].top, window.top, "Our subframe's top should be our top");
+ is(doGet("top", frames[0]), window.top,
+ "Our subframe's top should still be our top");
+
+ is(frames[0].window, frames[0], "window getter should work");
+ is(doGet("window", frames[0]), frames[0], "window getter should still work");
+ isnot(Object.getOwnPropertyDescriptor(window, "window").get, undefined,
+ "Should have a getter here");
+
+ // Finally, check that we can set the location
+ frames[0].location = "about:blank";
+ doSet("location", frames[1], "about:blank");
+
+ SimpleTest.finish();
+ }
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=946067">Mozilla Bug 946067</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+ <iframe id="x" src="http://www.example.com/nosuchpageIhope"></iframe>
+ <iframe id="y" src="http://www.example.com/nosuchpageIhope"></iframe>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_define_nonconfigurable.html b/dom/base/test/test_window_define_nonconfigurable.html
new file mode 100644
index 0000000000..9d35c687f0
--- /dev/null
+++ b/dom/base/test/test_window_define_nonconfigurable.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1107443
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1107443</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ var { AppConstants } = SpecialPowers.ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+ );
+
+ /**
+ * Test for Bug 1107443, modified when it was backed out in bug 1329323.
+ * This is now testing the _current_ behavior, not the desired one; expect
+ * failures in this test and needing to update it when bug 1329324 is
+ * fixed.
+ */
+ var retval = Object.defineProperty(window, "nosuchprop",
+ { value: 5, configurable: false });
+ todo_is(retval, null,
+ "Should return null when 'failing' to define non-configurable property via Object.defineProperty.")
+
+ var desc = Object.getOwnPropertyDescriptor(window, "nosuchprop");
+ is(typeof(desc), "object", "Should have a property 'nosuchprop' now");
+ todo_is(desc.configurable, true,
+ "Property 'nosuchprop' should be configurable");
+ is(desc.writable, false, "Property 'nosuchprop' should be readonly");
+ is(desc.value, 5, "Property 'nosuchprop' should have the right value");
+
+ retval = Object.defineProperties(window, {
+ "firstProp": { value: 1 },
+ "secondProp": { value: 2, configurable: false },
+ "thirdProp": { value: 3 },
+ });
+ todo_is(retval, null,
+ "Should return null when 'failing' to define non-configurable property via Object.defineProperties.")
+ // The properties should all be defined.
+ for (var [prop, val] of [["firstProp", 1], ["secondProp", 2], ["thirdProp", 3]]) {
+ desc = Object.getOwnPropertyDescriptor(window, prop);
+ is(typeof(desc), "object", `Should have a property '${prop}' now`);
+ todo_is(desc.configurable, true,
+ `Property '${prop}' should be configurable`);
+ is(desc.writable, false, `Property '${prop}' should be readonly`);
+ is(desc.value, val, `Property '${prop}' should have the right value`);
+ }
+
+ retval = Object.defineProperty(window, "nosuchprop2", { value: 6 });
+ is(retval, window,
+ "Should return object when succesfully defining 'nosuchprop2'");
+ desc = Object.getOwnPropertyDescriptor(window, "nosuchprop2");
+ is(typeof(desc), "object", "Should have a property 'nosuchprop2' now");
+ todo_is(desc.configurable, true,
+ "Property 'nosuchprop2' should be configurable");
+ is(desc.writable, false, "Property 'nosuchprop2' should be readonly");
+ is(desc.value, 6, "Property 'nosuchprop2' should have the right value");
+
+ retval = Object.defineProperty(window, "nosuchprop3",
+ { value: 7, configurable: true });
+ is(retval, window,
+ "Should return object when succesfully defining 'nosuchprop3'");
+ desc = Object.getOwnPropertyDescriptor(window, "nosuchprop3");
+ is(typeof(desc), "object", "Should have a property 'nosuchprop3' now");
+ is(desc.configurable, true,
+ "Property 'nosuchprop3' should be configurable");
+ is(desc.writable, false, "Property 'nosuchprop3' should be readonly");
+ is(desc.value, 7, "Property 'nosuchprop3' should have the right value");
+
+ retval = Reflect.defineProperty(window, "nosuchprop4",
+ { value: 8, configurable: false });
+ todo_is(retval, false,
+ "Should not be able to Reflect.defineProperty if non-configurable");
+ desc = Object.getOwnPropertyDescriptor(window, "nosuchprop4");
+ is(typeof(desc), "object", "Should have a property 'nosuchprop4' now");
+ todo_is(desc.configurable, true,
+ "Property 'nosuchprop4' should be configurable");
+ is(desc.writable, false, "Property 'nosuchprop4' should be readonly");
+ is(desc.value, 8, "Property 'nosuchprop4' should have the right value");
+
+ retval = Reflect.defineProperty(window, "nosuchprop5",
+ { value: 9 });
+ is(retval, true,
+ "Should be able to Reflect.defineProperty with default configurability");
+ desc = Object.getOwnPropertyDescriptor(window, "nosuchprop5");
+ is(typeof(desc), "object", "Should have a property 'nosuchprop5' now");
+ todo_is(desc.configurable, true,
+ "Property 'nosuchprop5' should be configurable");
+ is(desc.writable, false, "Property 'nosuchprop5' should be readonly");
+ is(desc.value, 9, "Property 'nosuchprop5' should have the right value");
+
+ retval = Reflect.defineProperty(window, "nosuchprop6",
+ { value: 10, configurable: true });
+ is(retval, true,
+ "Should be able to Reflect.defineProperty if configurable");
+ desc = Object.getOwnPropertyDescriptor(window, "nosuchprop6");
+ is(typeof(desc), "object", "Should have a property 'nosuchprop6' now");
+ is(desc.configurable, true, "Property 'nosuchprop6' should be configurable");
+ is(desc.writable, false, "Property 'nosuchprop6' should be readonly");
+ is(desc.value, 10, "Property 'nosuchprop6' should have the right value");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1107443">Mozilla Bug 1107443</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_define_symbol.html b/dom/base/test/test_window_define_symbol.html
new file mode 100644
index 0000000000..352e8e7736
--- /dev/null
+++ b/dom/base/test/test_window_define_symbol.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1082672
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1082672 part 2</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=1082672">Mozilla Bug 1082672</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+if (typeof Symbol === "function") {
+ var sym = Symbol("ponies");
+ Object.defineProperty(window, sym, {configurable: true, value: 3});
+ is(window[sym], 3);
+} else {
+ ok(true, "no Symbols in this build");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_element_enumeration.html b/dom/base/test/test_window_element_enumeration.html
new file mode 100644
index 0000000000..138fa89d6a
--- /dev/null
+++ b/dom/base/test/test_window_element_enumeration.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=959992
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 959992</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=959992">Mozilla Bug 959992</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <img id="one" name="two">
+ <div id="three" name="four"></div>
+ <div id=""></div>
+ <img name="">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 959992 **/
+ var names1 = Object.getOwnPropertyNames(window);
+ var names2 = [];
+ var gsp = Object.getPrototypeOf(Window.prototype);
+ var names3 = Object.getOwnPropertyNames(gsp);
+ for (var i in window) {
+ names2.push(i);
+ }
+
+ is(names1.indexOf(""), -1,
+ "Element with empty id/name should not be in our own prop list");
+ is(names2.indexOf(""), -1,
+ "Element with empty id/name name should not be in our enumeration list");
+ is(names3.indexOf(""), -1,
+ "Element with empty id/name should not be in GSP own prop list");
+
+ is(names1.indexOf("one"), -1,
+ "<img> with id should not be in our own prop list");
+ is(names2.indexOf("one"), -1,
+ "<img> with id should not be in our enumeration list");
+ isnot(names3.indexOf("one"), -1,
+ "<img> with id should be in GSP own prop list");
+
+ is(names1.indexOf("two"), -1,
+ "<img> with name should not be in our own prop list");
+ is(names2.indexOf("two"), -1,
+ "<img> with name should not be in our enumeration list");
+ isnot(names3.indexOf("two"), -1,
+ "<img> with name should be in GSP own prop list");
+
+ is(names1.indexOf("three"), -1,
+ "<div> with id should not be in our own prop list");
+ is(names2.indexOf("three"), -1,
+ "<div> with id should not be in our enumeration list");
+ todo_isnot(names3.indexOf("three"), -1,
+ "<div> with id should be in GSP own prop list");
+
+ is(names1.indexOf("four"), -1,
+ "<div> with name should not be in our own prop list");
+ is(names2.indexOf("four"), -1,
+ "<div> with name should not be in our enumeration list");
+ is(names3.indexOf("four"), -1,
+ "<div> with name should not be in GSP own prop list");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_enumeration.html b/dom/base/test/test_window_enumeration.html
new file mode 100644
index 0000000000..9d62741029
--- /dev/null
+++ b/dom/base/test/test_window_enumeration.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=807222
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 807222</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=807222">Mozilla Bug 807222</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 807222 **/
+var expectedProps = [ "Image", "Audio", "Option",
+ "PerformanceTiming", "CSS2Properties", "SVGElement" ];
+var actualProps = Object.getOwnPropertyNames(window);
+
+for (var i = 0; i < expectedProps.length; ++i) {
+ isnot(actualProps.indexOf(expectedProps[i]), -1,
+ "getOwnPropertyNames should include " + expectedProps[i]);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_extensible.html b/dom/base/test/test_window_extensible.html
new file mode 100644
index 0000000000..ddc6e0d3d0
--- /dev/null
+++ b/dom/base/test/test_window_extensible.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=856384
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 856384</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=856384">Mozilla Bug 856384</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe name="constructor" src="about:blank"></iframe>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function run()
+{
+ is(Object.isExtensible(window), true, "Windows are extensible by default");
+
+ try
+ {
+ Object.preventExtensions(window);
+ throw "didn't throw";
+ }
+ catch (e)
+ {
+ is(e instanceof TypeError, true,
+ "preventExtensions(window) should throw a TypeError, instead got: " + e);
+ is(Object.isExtensible(window), true,
+ 'Windows are extensible after an extensibility "change" attempt');
+ }
+
+ SimpleTest.finish();
+}
+
+window.addEventListener("load", run);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_focus_by_close_and_open.html b/dom/base/test/test_window_focus_by_close_and_open.html
new file mode 100644
index 0000000000..d9b833c26f
--- /dev/null
+++ b/dom/base/test/test_window_focus_by_close_and_open.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>test for window focus by window.close() and window.open()</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function start() {
+ var w = window.open("", "_blank");
+ w.finished = function() {
+ ok(true, "1st new window had focus");
+ w.close();
+ w = window.open("", "_blank");
+ w.finished = function() {
+ ok(true, "2nd new window had focus");
+ w.close();
+ SimpleTest.finish();
+ };
+ w.location = "file_window_focus_by_close_and_open.html";
+ };
+ w.location = "file_window_focus_by_close_and_open.html";
+}
+</script>
+</head>
+<body onload="setTimeout(start)">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1695135">Mozilla Bug 1695135</a>
+<p id="display"></p>
+<div id="content"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_indexing.html b/dom/base/test/test_window_indexing.html
new file mode 100644
index 0000000000..32713039b0
--- /dev/null
+++ b/dom/base/test/test_window_indexing.html
@@ -0,0 +1,139 @@
+
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=823228
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 823228</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=823228">Mozilla Bug 823228</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe name="x" id="x"></iframe>
+ <iframe name="y" id="y"></iframe>
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+
+ /** Test for Bug 823228 **/
+ is(window, window.frames, "These better be equal");
+ ok("0" in window, "We have a subframe");
+ ok("1" in window, "We have two subframes");
+ ok(!("2" in window), "But we don't have three subframes");
+ window[2] = "myString";
+ ok(!("2" in window), "Should not be able to set indexed expando");
+ Object.getPrototypeOf(window)[3] = "Hey there";
+ ok("3" in window, "Should be walking up the proto chain");
+
+ is(window[0].name, "x", "First frame is x");
+ is(window[1].name, "y", "Second frame is y");
+ is(window[2], undefined, "We should still not have our expando");
+ is(window[3], "Hey there", "We should still have our prop on the proto chain");
+
+ var x = $("x");
+ var y = $("y");
+
+ is(x.contentWindow, window[0], "First frame should have correct window");
+ is(y.contentWindow, window[1], "Second frame should have correct window");
+
+ // set() hook test
+ throws(TypeError, function () {
+ "use strict";
+ window[1] = "FAIL strict";
+ });
+
+ // set() hook test
+ window[1] = "FAIL";
+ is(window[1].name, "y", "Second frame is still y");
+ y.remove();
+ ok(!("1" in window), "We no longer have two subframes");
+ is(window[1], undefined, "We should not have a value here");
+
+ // defineProperty() hook test
+ function throws(errorCtor, f) {
+ try {
+ f();
+ } catch (exc) {
+ if (!(exc instanceof errorCtor))
+ throw exc;
+ return;
+ }
+ throw new Error("expected " + errCtor.name + ", no exception thrown: " + f);
+ }
+
+ x.parentNode.appendChild(y);
+ throws(TypeError, function () {
+ Object.defineProperty(window, "1", { value: "FAIL2", configurable: true,
+ writable: true });
+ });
+ y.remove();
+ ok(!("1" in window), "We no longer have two subframes, again");
+ is(window[1], undefined, "We should not have a value here either");
+
+ // More set() hook test
+ throws(TypeError, function () {
+ "use strict";
+ window[1] = "FAIL3 strict";
+ });
+ window[1] = "FAIL3";
+ ok(!("1" in window), "We shouldn't allow indexed expandos");
+ is(window[1], undefined, "We should not have a value for an indexed expando");
+ var desc = Object.getOwnPropertyDescriptor(window, "1");
+ is(desc, undefined, "We really really shouldn't have indexed expandos");
+
+ x.parentNode.appendChild(y);
+ is(window[1], y.contentWindow, "Second frame should now be visible");
+ desc = Object.getOwnPropertyDescriptor(window, "1");
+ ok(desc.configurable, "Subframe should be configurable");
+ ok(desc.enumerable, "Subframe should be configurable");
+ ok(!desc.writable, "Subframe should not be writable");
+ is(desc.value, y.contentWindow, "Subframe should have correct value");
+
+ y.remove();
+ is(window[1], undefined, "And now we should be back to no [1] property");
+
+ // And more defineProperty()
+ throws(TypeError, function () {
+ Object.defineProperty(window, "1", { value: "FAIL2", configurable: true,
+ writable: true });
+ });
+ ok(!("1" in window), "Defining indexed properties really just shouldn't work");
+ is(window[1], undefined, "Defining past end of list should not work");
+
+ // Enumeration tests
+ x.parentNode.appendChild(y);
+
+ var names = Object.getOwnPropertyNames(window);
+ is(names[0], "0", "Must start with 0");
+ is(names[1], "1", "Must continue with 1");
+ is(names.indexOf("2"), -1, "And 2, an attempted expando, should not be in there");
+ is(names.indexOf("3"), -1, "But no 3; that's on the proto");
+
+ names = [];
+ for (var name in window) {
+ names.push(name);
+ }
+ is(names[0], "0", "Enumeration must start with 0");
+ is(names[1], "1", "Enumeration must continue with 1");
+ is(names.indexOf("2"), -1, "Enumeration: but no expando 2");
+ isnot(names.indexOf("3"), -1, "Enumeration: and then 3, defined on the proto");
+ is(names.indexOf("4"), -1, "But no 4 around");
+
+ // Delete tests
+ is(delete window[1], false, "Deleting supported index should return false");
+ is(window[1], y.contentWindow, "Shouldn't be able to delete a supported index");
+ y.remove();
+ is(window[1], undefined,
+ "And now we should have no property here");
+ is(delete window[1], true, "Deleting unsupported index should return true");
+ is(window[1], undefined,
+ "And we shouldn't have things magically appear due to delete");
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_window_keys.html b/dom/base/test/test_window_keys.html
new file mode 100644
index 0000000000..8bbe6e2179
--- /dev/null
+++ b/dom/base/test/test_window_keys.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1372371
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1372371</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=1372371">Mozilla Bug 1372371</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe></iframe>
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+
+ /** Test for Bug 1372371 **/
+ var list = Object.keys(window);
+ is(list.indexOf("WebSocket"), -1, "WebSocket should not be enumerable");
+ is(list.indexOf("0"), 0, "Indexed props should be enumerable");
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_window_named_frame_enumeration.html b/dom/base/test/test_window_named_frame_enumeration.html
new file mode 100644
index 0000000000..d5436b1fee
--- /dev/null
+++ b/dom/base/test/test_window_named_frame_enumeration.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1019417
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1019417</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 1019417 **/
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(function() {
+ var names1 = Object.getOwnPropertyNames(window);
+ var names2 = [];
+ var gsp = Object.getPrototypeOf(Window.prototype);
+ var names3 = Object.getOwnPropertyNames(gsp);
+ for (var i in window) {
+ names2.push(i);
+ }
+
+ is(names1.indexOf(""), -1,
+ "Frame with no name or empty name should not be in our own prop list");
+ is(names2.indexOf(""), -1,
+ "Frame with no name or empty name should not be in our enumeration list");
+ is(names3.indexOf(""), -1,
+ "Frame with no name or empty name should not be in GSP own prop list");
+ is(names1.indexOf("x"), -1,
+ "Frame with about:blank loaded should not be in our own prop list");
+ is(names2.indexOf("x"), -1,
+ "Frame with about:blank loaded should not be in our enumeration list");
+ isnot(names3.indexOf("x"), -1,
+ "Frame with about:blank loaded should be in GSP own prop list");
+ is(names1.indexOf("y"), -1,
+ "Frame with same-origin loaded should not be in our own prop list");
+ is(names2.indexOf("y"), -1,
+ "Frame with same-origin loaded should not be in our enumeration list");
+ isnot(names3.indexOf("y"), -1,
+ "Frame with same-origin loaded should be in GSP own prop list");
+ is(names1.indexOf("z"), -1,
+ "Frame with cross-origin loaded should not be in our own prop list");
+ is(names2.indexOf("z"), -1,
+ "Frame with cross-origin loaded should not be in our enumeration list");
+ isnot(names3.indexOf("z"), -1,
+ "Frame with cross-origin loaded should be in GSP own prop list");
+ is(names1.indexOf("sameorigin"), -1,
+ "Frame with same-origin changed name should not be in our own prop list");
+ is(names2.indexOf("sameorigin"), -1,
+ "Frame with same-origin changed name should not be in our enumeration list");
+ isnot(names3.indexOf("sameorigin"), -1,
+ "Frame with same-origin changed name should be in GSP own prop list");
+ is(names1.indexOf("crossorigin"), -1,
+ "Frame with cross-origin changed name should not be in our own prop list");
+ is(names2.indexOf("crossorigin"), -1,
+ "Frame with cross-origin changed name should not be in our enumeration list");
+ is(names3.indexOf("crossorigin"), -1,
+ "Frame with cross-origin changed name should not be in GSP own prop list");
+
+ is(Object.getOwnPropertyDescriptor(gsp, ""), undefined,
+ "Should not have empty string as a named frame");
+ isnot(Object.getOwnPropertyDescriptor(gsp, "x"), undefined,
+ "Should have about:blank subframe as a named frame");
+ isnot(Object.getOwnPropertyDescriptor(gsp, "y"), undefined,
+ "Should have same-origin subframe as a named frame");
+ isnot(Object.getOwnPropertyDescriptor(gsp, "z"), undefined,
+ "Should have cross-origin subframe as a named frame");
+ isnot(Object.getOwnPropertyDescriptor(gsp, "sameorigin"), undefined,
+ "Should have same-origin changed name as a named frame");
+ is(Object.getOwnPropertyDescriptor(gsp, "crossorigin"), undefined,
+ "Should not have cross-origin-origin changed name as a named frame");
+ SimpleTest.finish();
+ });
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1019417">Mozilla Bug 1019417</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+<iframe name=""></iframe>
+<iframe name="x"></iframe>
+<iframe name="y"
+ src="http://mochi.test:8888/tests/dom/base/test/file_empty.html"></iframe>
+<iframe name="z"
+ src="http://example.com/tests/dom/base/test/file_empty.html"></iframe>
+<iframe name="v"
+ src="http://mochi.test:8888/tests/dom/base/test/file_setname.html?sameorigin"></iframe>
+<iframe name="w"
+ src="http://example.com/tests/dom/base/test/file_setname.html?crossorigin"></iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_window_own_props.html b/dom/base/test/test_window_own_props.html
new file mode 100644
index 0000000000..55322e3b1e
--- /dev/null
+++ b/dom/base/test/test_window_own_props.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1372371
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1372371</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=1372371">Mozilla Bug 1372371</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe></iframe>
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+
+ /** Test for Bug 1372371 **/
+ var list = Object.getOwnPropertyNames(window);
+ // Pick an interface name we would not have resolved here yet.
+ isnot(list.indexOf("WebSocket"), -1, "WebSocket should be a property");
+ is(list.indexOf("0"), 0, "Indexed props should be properties");
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/test_window_proto.html b/dom/base/test/test_window_proto.html
new file mode 100644
index 0000000000..944f953bc4
--- /dev/null
+++ b/dom/base/test/test_window_proto.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for ...</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws(new TypeError, function() {
+ Object.setPrototypeOf(window, Object.create(window));
+ }, "Setting prototype via setPrototypeOf");
+
+ assert_throws(new TypeError, function() {
+ window.__proto__ = Object.create(window);
+ }, "Setting prototype via __proto__");
+}, "Setting the prototype of a window to something that has the window on its proto chain should throw");
+</script>
diff --git a/dom/base/test/test_writable-replaceable.html b/dom/base/test/test_writable-replaceable.html
new file mode 100644
index 0000000000..422e0d67a6
--- /dev/null
+++ b/dom/base/test/test_writable-replaceable.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 823283</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=823283">Mozilla Bug 823283</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 823283 **/
+
+function createTest(prop, typeStr, valCode, replaceable)
+{
+ var newType = replaceable ? typeof(valCode) : typeStr;
+ var code =
+ 'is(typeof ' + prop + ', "' + typeStr + '", "' + prop + ': bad unqualified before-state");\n' +
+ 'is(typeof window.' + prop + ', "' + typeStr + '", "' + prop + ': bad qualified before-state");\n' +
+ '\n' +
+ prop + ' = ' + valCode + ';\n' +
+ '\n' +
+ 'is(typeof ' + prop + ', "' + newType + '", "' + prop + ': bad unqualified after-state");\n' +
+ 'is(typeof window.' + prop + ', "' + newType + '", "' + prop + ': bad qualified after-state");';
+
+ return Function(code);
+}
+
+[
+ ["innerHeight", "number", '"123"', true],
+ ["innerWidth", "number", '"456"', true],
+ ["outerHeight", "number", '"654"', true],
+ ["outerWidth", "number", '"321"', true],
+ ["screenX", "number", '"17"', true],
+ ["screenY", "number", '"42"', true],
+ ["status", "string", '{}', false],
+ ["name", "string", '{}', false],
+].forEach(function(args)
+{
+ createTest.apply(null, args)();
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/test_x-frame-options.html b/dom/base/test/test_x-frame-options.html
new file mode 100644
index 0000000000..d8586e7974
--- /dev/null
+++ b/dom/base/test/test_x-frame-options.html
@@ -0,0 +1,195 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for X-Frame-Options response header</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>
+
+<iframe style="width:100%;height:300px;" id="harness"></iframe>
+<script class="testbody" type="text/javascript">
+
+var path = "/tests/dom/base/test/";
+
+var testFramesLoaded = async function() {
+ var harness = document.getElementById("harness").contentDocument;
+
+ // iframe from same origin, no X-F-O header - should load
+ var frame = harness.getElementById("control1");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test1 = this.content.document.getElementById("test").textContent;
+ Assert.equal(test1, "control1", "test control1");
+ });
+
+ // iframe from different origin, no X-F-O header - should load
+ frame = harness.getElementById("control2");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test2 = this.content.document.getElementById("test").textContent;
+ Assert.equal(test2, "control2", "test control2");
+ });
+
+ // iframe from same origin, X-F-O: DENY - should not load
+ frame = harness.getElementById("deny");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test3 = this.content.document.getElementById("test");
+ Assert.equal(test3, null, "test deny");
+ });
+
+ // iframe from same origin, X-F-O: SAMEORIGIN - should load
+ frame = harness.getElementById("sameorigin1");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test4 = this.content.document.getElementById("test").textContent;
+ Assert.equal(test4, "sameorigin1", "test sameorigin1");
+ });
+
+ // iframe from different origin, X-F-O: SAMEORIGIN - should not load
+ frame = harness.getElementById("sameorigin2");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test5 = this.content.document.getElementById("test");
+ Assert.equal(test5, null, "test sameorigin2");
+ });
+
+ // iframe from different origin, X-F-O: SAMEORIGIN, SAMEORIGIN - should not load
+ frame = harness.getElementById("sameorigin5");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test6 = this.content.document.getElementById("test");
+ Assert.equal(test6, null, "test sameorigin5");
+ });
+
+ // iframe from same origin, X-F-O: SAMEORIGIN, SAMEORIGIN - should load
+ frame = harness.getElementById("sameorigin6");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test7 = this.content.document.getElementById("test").textContent;
+ Assert.equal(test7, "sameorigin6", "test sameorigin6");
+ });
+
+ // iframe from same origin, X-F-O: SAMEORIGIN,SAMEORIGIN, SAMEORIGIN - should load
+ frame = harness.getElementById("sameorigin7");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test8 = this.content.document.getElementById("test").textContent;
+ Assert.equal(test8, "sameorigin7", "test sameorigin7");
+ });
+
+ // iframe from same origin, X-F-O: SAMEORIGIN,SAMEORIGIN, SAMEORIGIN - should not load
+ frame = harness.getElementById("sameorigin8");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test9 = this.content.document.getElementById("test");
+ Assert.equal(test9, null, "test sameorigin8");
+ });
+
+ // iframe from same origin, X-F-O: DENY,SAMEORIGIN - should not load
+ frame = harness.getElementById("mixedpolicy");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test10 = this.content.document.getElementById("test");
+ Assert.equal(test10, null, "test mixedpolicy");
+ });
+
+ // iframe from different origin, allow-from: this origin - should load
+ frame = harness.getElementById("allow-from-allow");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test11 = this.content.document.getElementById("test").textContent;
+ Assert.equal(test11, "allow-from-allow", "test allow-from-allow");
+ });
+
+ // iframe from different origin, with allow-from: other - should load as we no longer support allow-from (Bug 1301529)
+ frame = harness.getElementById("allow-from-deny");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test12 = this.content.document.getElementById("test");
+ Assert.notEqual(test12, null, "test allow-from-deny");
+ });
+
+ // iframe from different origin, X-F-O: SAMEORIGIN, multipart - should not load
+ frame = harness.getElementById("sameorigin-multipart");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test13 = this.content.document.getElementById("test");
+ Assert.equal(test13, null, "test sameorigin-multipart");
+ });
+
+ // iframe from same origin, X-F-O: SAMEORIGIN, multipart - should load
+ frame = harness.getElementById("sameorigin-multipart2");
+ await SpecialPowers.spawn(frame, [], () => {
+ var test14 = this.content.document.getElementById("test").textContent;
+ Assert.equal(test14, "sameorigin-multipart2", "test sameorigin-multipart2");
+ });
+
+
+ // frames from bug 836132 tests, no longer supported allow-from
+ {
+ frame = harness.getElementById("allow-from-allow-1");
+ var theTestResult = frame.contentDocument.getElementById("test");
+ isnot(theTestResult, null, "test afa1 should have been allowed");
+ if(theTestResult) {
+ is(theTestResult.textContent, "allow-from-allow-1", "test allow-from-allow-1");
+ }
+ }
+ // Verify allow-from no longer works
+ for (var i = 1; i<=14; i++) {
+ frame = harness.getElementById("allow-from-deny-" + i);
+ var theTestResult = frame.contentDocument.getElementById("test");
+ isnot(theTestResult, null, "test allow-from-deny-" + i);
+ }
+
+ // call tests to check principal comparison, e.g. a document can open a window
+ // to a data: or javascript: document which frames an
+ // X-Frame-Options: SAMEORIGIN document and the frame should load
+ testFrameInJSURI();
+};
+
+// test that a document can be framed under a javascript: URL opened by the
+// same site as the frame
+// We can't set a load event listener before calling document.open/document.write, because those will remove such listeners. So we need to define a function that the new window will be able to call.
+function frameInJSURILoaded(win) {
+ var test = win.document.getElementById("sameorigin3")
+ .contentDocument.getElementById("test");
+ ok(test != null, "frame under javascript: URL should have loaded.");
+ win.close();
+
+ testFrameNotLoadedInDataURI();
+}
+
+var testFrameInJSURI = function() {
+ var html = '<iframe id="sameorigin3" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin3&xfo=sameorigin"></iframe>';
+ var win = window.open();
+ win.location.href = "javascript:document.open(); onload = opener.frameInJSURILoaded.bind(null, window); document.write('"+html+"');document.close();";
+};
+
+// test an iframe with X-FRAME-OPTIONS shouldn't be loaded in a cross-origin window,
+var testFrameNotLoadedInDataURI = function() {
+ // In this case we load two iframes, one is sameorigin4, which will have X-FRAME-OPTIONS,
+ // the other is postmessage, which won't get the XFO header.
+ // And because now window is navigated to a data: URI, which is considered as cross origin,
+ // So win.onload won't be fired, so we use the iframe 'postmessage' to know the iframes
+ // have been loaded.
+ var html = `<iframe id="sameorigin4" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=sameorigin4&xfo=sameorigin"></iframe>
+ <iframe id="postmessage" src="http://mochi.test:8888/tests/dom/base/test/file_x-frame-options_page.sjs?testid=postmessage"></iframe>`;
+ var win = window.open();
+ window.onmessage = function(evt) {
+ var iframe = SpecialPowers.wrap(win).document.getElementById("sameorigin4");
+ var test = iframe.contentDocument.getElementById("test");
+ ok(test == null, "frame under data: URL should have blocked.");
+ win.close();
+
+ SimpleTest.finish();
+ };
+ win.location.href = "data:text/html,"+html;
+};
+
+SimpleTest.waitForExplicitFinish();
+
+// load the test harness
+SpecialPowers.pushPrefEnv({
+ "set": [["security.data_uri.block_toplevel_data_uri_navigations", false],]
+}, function() {
+ document.getElementById("harness").src = "file_x-frame-options_main.html";
+});
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/base/test/test_youtube_flash_embed.html b/dom/base/test/test_youtube_flash_embed.html
new file mode 100644
index 0000000000..2c7cddaefd
--- /dev/null
+++ b/dom/base/test/test_youtube_flash_embed.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1240471
+ -->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1240471</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ let path = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/file_youtube_flash_embed.html';
+ onmessage = function(e) {
+ let msg = JSON.parse(e.data);
+ if (msg.fn == "finish") {
+ SimpleTest.finish();
+ return;
+ }
+ self[msg.fn].apply(null, msg.args);
+ }
+ function onLoad() {
+ // The test file must be loaded into youtube.com domain
+ // because it needs unprivileged access to fullscreenEnabled.
+ ifr.src = "https://mochitest.youtube.com" + path;
+ }
+ </script>
+ </head>
+ <body onload="onLoad()">
+ <iframe id="ifr" allowfullscreen></iframe>
+ </body>
+</html>
diff --git a/dom/base/test/unit/1_original.xml b/dom/base/test/unit/1_original.xml
new file mode 100644
index 0000000000..4b7915159d
--- /dev/null
+++ b/dom/base/test/unit/1_original.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+
+<foo /> <!-- é --> \ No newline at end of file
diff --git a/dom/base/test/unit/1_result.xml b/dom/base/test/unit/1_result.xml
new file mode 100644
index 0000000000..61d4458be9
--- /dev/null
+++ b/dom/base/test/unit/1_result.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<foo/>
+<!-- é --> \ No newline at end of file
diff --git a/dom/base/test/unit/2_original.xml b/dom/base/test/unit/2_original.xml
new file mode 100644
index 0000000000..16eeb817ff
--- /dev/null
+++ b/dom/base/test/unit/2_original.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="htp://mozilla.org/ns">
+ <baz/><!-- a comment --> <bar> &lt;robots&gt; &amp; &lt;aliens&gt;
+<mozilla> a a a a a éèàùûî</mozilla>
+ <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi at odio consectetuer molestie.</firefox>
+ <?xml-foo "hey" ?>
+</bar>
+ <!-- a comment
+ on several lines-->
+ <?xml-foo "another pi on two lines"
+ example="hello"?>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/2_result_1.xml b/dom/base/test/unit/2_result_1.xml
new file mode 100644
index 0000000000..16eeb817ff
--- /dev/null
+++ b/dom/base/test/unit/2_result_1.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="htp://mozilla.org/ns">
+ <baz/><!-- a comment --> <bar> &lt;robots&gt; &amp; &lt;aliens&gt;
+<mozilla> a a a a a éèàùûî</mozilla>
+ <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi at odio consectetuer molestie.</firefox>
+ <?xml-foo "hey" ?>
+</bar>
+ <!-- a comment
+ on several lines-->
+ <?xml-foo "another pi on two lines"
+ example="hello"?>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/2_result_2.xml b/dom/base/test/unit/2_result_2.xml
new file mode 100644
index 0000000000..c3eeadb58f
--- /dev/null
+++ b/dom/base/test/unit/2_result_2.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="htp://mozilla.org/ns">
+ <baz/><!-- a comment -->
+ <bar> &lt;robots&gt; &amp; &lt;aliens&gt;
+ <mozilla> a a a a a éèàùûî</mozilla>
+ <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi at odio consectetuer molestie.</firefox>
+ <?xml-foo "hey" ?>
+ </bar>
+ <!-- a comment
+ on several lines-->
+ <?xml-foo "another pi on two lines"
+ example="hello"?>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/2_result_3.xml b/dom/base/test/unit/2_result_3.xml
new file mode 100644
index 0000000000..906ac89ee5
--- /dev/null
+++ b/dom/base/test/unit/2_result_3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="htp://mozilla.org/ns">
+ <baz/><!-- a comment -->
+ <bar> &lt;robots&gt; &amp; &lt;aliens&gt;
+ <mozilla> a a a a a éèàùûî</mozilla>
+ <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer
+ adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis
+ ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent
+ taciti sociosqu ad litora torquent per conubia nostra, per
+ inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum
+ sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris
+ quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum
+ posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia
+ libero ullamcorper laoreet. Cras quis nisi at odio consectetuer
+ molestie.</firefox>
+ <?xml-foo "hey" ?>
+ </bar>
+ <!-- a comment
+ on several lines-->
+ <?xml-foo "another pi on two lines"
+ example="hello"?>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/2_result_4.xml b/dom/base/test/unit/2_result_4.xml
new file mode 100644
index 0000000000..27ed219211
--- /dev/null
+++ b/dom/base/test/unit/2_result_4.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="htp://mozilla.org/ns">
+ <baz/><!-- a comment --> <bar> &lt;robots&gt; &amp; &lt;aliens&gt;
+<mozilla> a a a a a éèàùûî</mozilla>
+ <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer
+adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum.
+Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti
+sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos.
+Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac,
+est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non
+ lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec
+ sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi
+at odio consectetuer molestie.</firefox>
+ <?xml-foo "hey" ?>
+</bar>
+ <!-- a comment
+ on several lines-->
+ <?xml-foo "another pi on two lines"
+ example="hello"?>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/3_original.xml b/dom/base/test/unit/3_original.xml
new file mode 100644
index 0000000000..eb9c1bd656
--- /dev/null
+++ b/dom/base/test/unit/3_original.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<foo>
+Lorem ip<!-- aaa -->sum dolorsitamet, consectetuer adipiscing elit. Nameusapien. Sed viverralacus. this_is_a_very_long_long_word_which_has_a_length_higher_than_the_max_column Donecquisipsum. Nunc cursus aliquet lectus. Nunc vitae eros.
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/3_result.xml b/dom/base/test/unit/3_result.xml
new file mode 100644
index 0000000000..e556c61e58
--- /dev/null
+++ b/dom/base/test/unit/3_result.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<foo>
+ Lorem ip<!-- aaa -->sum dolorsitamet, consectetuer adipiscing elit.
+ Nameusapien. Sed viverralacus.
+ this_is_a_very_long_long_word_which_has_a_length_higher_than_the_max_column
+ Donecquisipsum. Nunc cursus aliquet lectus. Nunc vitae eros.
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/3_result_2.xml b/dom/base/test/unit/3_result_2.xml
new file mode 100644
index 0000000000..2df257ca75
--- /dev/null
+++ b/dom/base/test/unit/3_result_2.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<foo>
+Lorem ip<!-- aaa -->sum dolorsitamet, consectetuer adipiscing elit.
+Nameusapien. Sed viverralacus.
+this_is_a_very_long_long_word_which_has_a_length_higher_than_the_max_column
+ Donecquisipsum. Nunc cursus aliquet lectus. Nunc vitae eros.
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/4_original.xml b/dom/base/test/unit/4_original.xml
new file mode 100644
index 0000000000..b985da960e
--- /dev/null
+++ b/dom/base/test/unit/4_original.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="http://mozilla.org/ns" xmlns:falsexul="http://mozilla.org/ns3">
+ <!-- document to test namespaces-->
+ <baz/>
+ <bar> &lt;robots&gt; &amp; &lt;aliens&gt;
+ <mozilla xmlns="http://mozilla.org/ns2"> a a a <moz>a a</moz> éèàùûî</mozilla>
+ <firefox>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</firefox>
+ </bar>
+
+ <xul xmlns="http://mozilla.org/ns3" xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description other:yes="no">xul fake</description>
+ </box>
+ </xul>
+
+ <falsexul:xul xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description>xul fake</description>
+ <what xmlns="http://mozilla.org/ns/other">lorem ipsum <falsexul:label value="hello"/> the return</what>
+ </box>
+ </falsexul:xul>
+
+ <ho:xul xmlns="http://mozilla.org/ns4" xmlns:ho="http://mozilla.org/ns4" xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description ho:foo="bar" bla="hello" other:yes="no" ho:foo2="bar2">xul fake</description>
+ </box>
+ </ho:xul>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/4_result_1.xml b/dom/base/test/unit/4_result_1.xml
new file mode 100644
index 0000000000..b985da960e
--- /dev/null
+++ b/dom/base/test/unit/4_result_1.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="http://mozilla.org/ns" xmlns:falsexul="http://mozilla.org/ns3">
+ <!-- document to test namespaces-->
+ <baz/>
+ <bar> &lt;robots&gt; &amp; &lt;aliens&gt;
+ <mozilla xmlns="http://mozilla.org/ns2"> a a a <moz>a a</moz> éèàùûî</mozilla>
+ <firefox>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</firefox>
+ </bar>
+
+ <xul xmlns="http://mozilla.org/ns3" xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description other:yes="no">xul fake</description>
+ </box>
+ </xul>
+
+ <falsexul:xul xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description>xul fake</description>
+ <what xmlns="http://mozilla.org/ns/other">lorem ipsum <falsexul:label value="hello"/> the return</what>
+ </box>
+ </falsexul:xul>
+
+ <ho:xul xmlns="http://mozilla.org/ns4" xmlns:ho="http://mozilla.org/ns4" xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description ho:foo="bar" bla="hello" other:yes="no" ho:foo2="bar2">xul fake</description>
+ </box>
+ </ho:xul>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/4_result_2.xml b/dom/base/test/unit/4_result_2.xml
new file mode 100644
index 0000000000..bc408b431c
--- /dev/null
+++ b/dom/base/test/unit/4_result_2.xml
@@ -0,0 +1,7 @@
+<falsexul:xul xmlns:falsexul="http://mozilla.org/ns3" xmlns:other="http://mozilla.org/ns/other">
+ <box xmlns="http://mozilla.org/ns">
+ <other:what>lorem ipsum</other:what>
+ <description>xul fake</description>
+ <what xmlns="http://mozilla.org/ns/other">lorem ipsum <falsexul:label value="hello"/> the return</what>
+ </box>
+ </falsexul:xul> \ No newline at end of file
diff --git a/dom/base/test/unit/4_result_3.xml b/dom/base/test/unit/4_result_3.xml
new file mode 100644
index 0000000000..30c8b47de7
--- /dev/null
+++ b/dom/base/test/unit/4_result_3.xml
@@ -0,0 +1,4 @@
+<box xmlns="http://mozilla.org/ns3">
+ <other:what xmlns:other="http://mozilla.org/ns/other">lorem ipsum</other:what>
+ <description other:yes="no" xmlns:other="http://mozilla.org/ns/other">xul fake</description>
+ </box> \ No newline at end of file
diff --git a/dom/base/test/unit/4_result_4.xml b/dom/base/test/unit/4_result_4.xml
new file mode 100644
index 0000000000..9346d5d170
--- /dev/null
+++ b/dom/base/test/unit/4_result_4.xml
@@ -0,0 +1,4 @@
+<box xmlns="http://mozilla.org/ns4">
+ <other:what xmlns:other="http://mozilla.org/ns/other">lorem ipsum</other:what>
+ <description ho:foo="bar" xmlns:ho="http://mozilla.org/ns4" bla="hello" other:yes="no" xmlns:other="http://mozilla.org/ns/other" ho:foo2="bar2">xul fake</description>
+ </box> \ No newline at end of file
diff --git a/dom/base/test/unit/4_result_5.xml b/dom/base/test/unit/4_result_5.xml
new file mode 100644
index 0000000000..4bb152576a
--- /dev/null
+++ b/dom/base/test/unit/4_result_5.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="http://mozilla.org/ns"
+xmlns:falsexul="http://mozilla.org/ns3">
+ <!-- document to test namespaces-->
+ <baz/>
+ <bar> &lt;robots&gt; &amp;
+ &lt;aliens&gt;
+ <mozilla
+ xmlns="http://mozilla.org/ns2"> a
+ a a
+ <moz>a a</moz> éèàùûî</mozilla>
+ <firefox>Lorem ipsum dolor sit amet,
+ consectetuer adipiscing elit.</firefox>
+ </bar>
+ <xul xmlns="http://mozilla.org/ns3"
+xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description other:yes="no">xul
+ fake</description>
+ </box>
+ </xul>
+ <falsexul:xul
+xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description>xul fake</description>
+ <what
+xmlns="http://mozilla.org/ns/other">lorem
+ ipsum
+ <falsexul:label value="hello"/>
+ the return</what>
+ </box>
+ </falsexul:xul>
+ <ho:xul xmlns="http://mozilla.org/ns4"
+ xmlns:ho="http://mozilla.org/ns4"
+xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description ho:foo="bar"
+ bla="hello" other:yes="no"
+ ho:foo2="bar2">xul fake</description>
+ </box>
+ </ho:xul>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/4_result_6.xml b/dom/base/test/unit/4_result_6.xml
new file mode 100644
index 0000000000..ce18f72a81
--- /dev/null
+++ b/dom/base/test/unit/4_result_6.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo">
+<foo xmlns="http://mozilla.org/ns"
+xmlns:falsexul="http://mozilla.org/ns3">
+ <!-- document to test namespaces-->
+ <baz/>
+ <bar> &lt;robots&gt; &amp;
+&lt;aliens&gt;
+ <mozilla
+xmlns="http://mozilla.org/ns2"> a a a <moz>a
+ a</moz> éèàùûî</mozilla>
+ <firefox>Lorem ipsum dolor sit
+amet, consectetuer adipiscing elit.</firefox>
+ </bar>
+
+ <xul xmlns="http://mozilla.org/ns3"
+xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description other:yes="no">xul
+fake</description>
+ </box>
+ </xul>
+
+ <falsexul:xul
+xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description>xul fake</description>
+ <what
+xmlns="http://mozilla.org/ns/other">lorem
+ ipsum <falsexul:label value="hello"/>
+the return</what>
+ </box>
+ </falsexul:xul>
+
+ <ho:xul
+xmlns="http://mozilla.org/ns4"
+xmlns:ho="http://mozilla.org/ns4"
+xmlns:other="http://mozilla.org/ns/other">
+ <box>
+ <other:what>lorem ipsum</other:what>
+ <description ho:foo="bar"
+bla="hello" other:yes="no"
+ho:foo2="bar2">xul fake</description>
+ </box>
+ </ho:xul>
+</foo> \ No newline at end of file
diff --git a/dom/base/test/unit/empty_document.xml b/dom/base/test/unit/empty_document.xml
new file mode 100644
index 0000000000..ebd60b08c7
--- /dev/null
+++ b/dom/base/test/unit/empty_document.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" ?>
+<!-- empty document for use in tests that don't need any particular DOM -->
+<root/>
diff --git a/dom/base/test/unit/head_utilities.js b/dom/base/test/unit/head_utilities.js
new file mode 100644
index 0000000000..4b6d41ff1b
--- /dev/null
+++ b/dom/base/test/unit/head_utilities.js
@@ -0,0 +1,69 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
+/* 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/. */
+
+var {
+ HTTP_400,
+ HTTP_401,
+ HTTP_402,
+ HTTP_403,
+ HTTP_404,
+ HTTP_405,
+ HTTP_406,
+ HTTP_407,
+ HTTP_408,
+ HTTP_409,
+ HTTP_410,
+ HTTP_411,
+ HTTP_412,
+ HTTP_413,
+ HTTP_414,
+ HTTP_415,
+ HTTP_417,
+ HTTP_500,
+ HTTP_501,
+ HTTP_502,
+ HTTP_503,
+ HTTP_504,
+ HTTP_505,
+ HttpError,
+ HttpServer,
+} = ChromeUtils.import("resource://testing-common/httpd.js");
+var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+const nsIDocumentEncoder = Ci.nsIDocumentEncoder;
+const replacementChar =
+ Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
+
+function loadContentFile(aFile, aCharset) {
+ // if(aAsIso == undefined) aAsIso = false;
+ if (aCharset == undefined) {
+ aCharset = "UTF-8";
+ }
+
+ var file = do_get_file(aFile);
+
+ var chann = NetUtil.newChannel({
+ uri: Services.io.newFileURI(file),
+ loadUsingSystemPrincipal: true,
+ });
+ chann.contentCharset = aCharset;
+
+ /* var inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
+ .createInstance(Components.interfaces.nsIScriptableInputStream);
+ inputStream.init(chann.open());
+ return inputStream.read(file.fileSize);
+ */
+
+ var inputStream = Cc[
+ "@mozilla.org/intl/converter-input-stream;1"
+ ].createInstance(Ci.nsIConverterInputStream);
+ inputStream.init(chann.open(), aCharset, 1024, replacementChar);
+ var str = {},
+ content = "";
+ while (inputStream.readString(4096, str) != 0) {
+ content += str.value;
+ }
+ return content;
+}
diff --git a/dom/base/test/unit/head_xml.js b/dom/base/test/unit/head_xml.js
new file mode 100644
index 0000000000..ed96926c80
--- /dev/null
+++ b/dom/base/test/unit/head_xml.js
@@ -0,0 +1,152 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+const I = Ci;
+const C = Cc;
+
+const nsIFile = I.nsIFile;
+const nsIProperties = I.nsIProperties;
+const nsIFileInputStream = I.nsIFileInputStream;
+const nsIInputStream = I.nsIInputStream;
+
+function getParser() {
+ var parser = new DOMParser();
+ parser.forceEnableXULXBL();
+ return parser;
+}
+
+var __testsDirectory = null;
+
+function ParseFile(file) {
+ if (typeof file == "string") {
+ if (!__testsDirectory) {
+ __testsDirectory = do_get_cwd();
+ }
+ var fileObj = __testsDirectory.clone();
+ fileObj.append(file);
+ file = fileObj;
+ }
+
+ Assert.equal(file instanceof nsIFile, true);
+
+ var fileStr =
+ C["@mozilla.org/network/file-input-stream;1"].createInstance(
+ nsIFileInputStream
+ );
+ // Init for readonly reading
+ fileStr.init(file, 0x01, 0o400, nsIFileInputStream.CLOSE_ON_EOF);
+ return ParseXML(fileStr);
+}
+
+function ParseXML(data) {
+ if (typeof data == "string") {
+ return getParser().parseFromString(data, "application/xml");
+ }
+
+ Assert.equal(data instanceof nsIInputStream, true);
+
+ return getParser().parseFromStream(
+ data,
+ "UTF-8",
+ data.available(),
+ "application/xml"
+ );
+}
+
+function DOMSerializer() {
+ return new XMLSerializer();
+}
+
+function SerializeXML(node) {
+ return DOMSerializer().serializeToString(node);
+}
+
+function roundtrip(obj) {
+ if (typeof obj == "string") {
+ return SerializeXML(ParseXML(obj));
+ }
+
+ Assert.equal(Node.isInstance(obj), true);
+ return ParseXML(SerializeXML(obj));
+}
+
+function do_compare_attrs(e1, e2) {
+ const xmlns = "http://www.w3.org/2000/xmlns/";
+
+ var a1 = e1.attributes;
+ var a2 = e2.attributes;
+ for (var i = 0; i < a1.length; ++i) {
+ var att = a1.item(i);
+ // Don't test for namespace decls, since those can just sorta be
+ // scattered about
+ if (att.namespaceURI != xmlns) {
+ var att2 = a2.getNamedItemNS(att.namespaceURI, att.localName);
+ if (!att2) {
+ do_throw(
+ "Missing attribute with namespaceURI '" +
+ att.namespaceURI +
+ "' and localName '" +
+ att.localName +
+ "'"
+ );
+ }
+ Assert.equal(att.value, att2.value);
+ }
+ }
+}
+
+function do_check_equiv(dom1, dom2) {
+ Assert.equal(dom1.nodeType, dom2.nodeType);
+ switch (dom1.nodeType) {
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ Assert.equal(dom1.target, dom2.target);
+ Assert.equal(dom1.data, dom2.data);
+ // fall through
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ case Node.COMMENT_NODE:
+ Assert.equal(dom1.data, dom2.data);
+ break;
+ case Node.ELEMENT_NODE:
+ Assert.equal(dom1.namespaceURI, dom2.namespaceURI);
+ Assert.equal(dom1.localName, dom2.localName);
+ // Compare attrs in both directions -- do_compare_attrs does a
+ // subset check.
+ do_compare_attrs(dom1, dom2);
+ do_compare_attrs(dom2, dom1);
+ // Fall through
+ case Node.DOCUMENT_NODE:
+ Assert.equal(dom1.childNodes.length, dom2.childNodes.length);
+ for (var i = 0; i < dom1.childNodes.length; ++i) {
+ do_check_equiv(dom1.childNodes.item(i), dom2.childNodes.item(i));
+ }
+ break;
+ }
+}
+
+function do_check_serialize(dom) {
+ do_check_equiv(dom, roundtrip(dom));
+}
+
+function Pipe() {
+ var p = C["@mozilla.org/pipe;1"].createInstance(I.nsIPipe);
+ p.init(false, false, 0, 0xffffffff, null);
+ return p;
+}
+
+function ScriptableInput(arg) {
+ if (arg instanceof I.nsIPipe) {
+ arg = arg.inputStream;
+ }
+
+ var str = C["@mozilla.org/scriptableinputstream;1"].createInstance(
+ I.nsIScriptableInputStream
+ );
+
+ str.init(arg);
+
+ return str;
+}
diff --git a/dom/base/test/unit/isequalnode_data.xml b/dom/base/test/unit/isequalnode_data.xml
new file mode 100644
index 0000000000..4b72f5d502
--- /dev/null
+++ b/dom/base/test/unit/isequalnode_data.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" ?>
+<!DOCTYPE Test [
+ <!ATTLIST test id ID #REQUIRED>
+]>
+
+<root>
+
+ <test id="test_setAttribute">
+ <foo/>
+ <foo/>
+ </test>
+
+ <test id="test_normalization">
+ <bar/>
+ <bar/>
+ </test>
+
+ <test id="test_whitespace">
+
+ <!--
+ Tests here consist of isEqualNode comparisons of the first and third
+ (zero-indexed) child nodes of each test.
+
+ In the typical case this means that the zeroth, second, and fourth
+ children are whitespace and the first and third are the nodes being
+ compared for equality or inequality.
+
+ In some cases, however, where either node is a Text node, this pattern
+ must of necessity be violated. Examples of such tests include the
+ test_text# tests.
+
+ As a result of this, BE CAREFUL NOT TO INTRODUCE STRAY WHITESPACE WHEN
+ EDITING THIS FILE. You have been warned.
+ -->
+
+ <test id="test_pi1">
+ <?pi data?>
+ <?pi data?>
+ </test>
+ <test id="test_pi2">
+ <?pi data?>
+ <?pi data?>
+ </test>
+ <test id="test_pi3">
+ <?pi data?>
+ <?pi data ?>
+ </test>
+ <test id="test_pi4">
+ <?pi ?>
+ <?pi ?>
+ </test>
+ <test id="test_pi5">
+ <?pi?>
+ <?pi ?>
+ </test>
+
+ <test id="test_elt1">
+ <foo></foo>
+ <foo> </foo>
+ </test>
+ <test id="test_elt2">
+ <foo></foo>
+ <foo>
+</foo>
+ </test>
+ <test id="test_elt3">
+ <foo ></foo>
+ <foo></foo>
+ </test>
+ <test id="test_elt4">
+ <bar xmlns="http://example.com/"/>
+ <bar/>
+ </test>
+ <test id="test_elt5">
+ <bar xmlns="http://example.com/"/>
+ <bar xmlns="http://example.com"/>
+ </test>
+
+ <test id="test_comment1">
+ <!--foo-->
+ <!--foo-->
+ </test>
+ <test id="test_comment2">
+ <!--foo-->
+ <!--foo -->
+ </test>
+ <test id="test_comment3">
+ <!--foo-->
+ <!--foo
+-->
+ </test>
+ <test id="test_comment4">
+ <!--
+foo-->
+ <!--
+foo-->
+ </test>
+
+ <test id="test_text1"><placeholder-dont-move/>
+<placeholder-dont-move/>
+<placeholder-dont-move/>
+ </test>
+ <test id="test_text2"><placeholder-dont-move/>
+<placeholder-dont-move/> <placeholder-dont-move/>
+ </test>
+ <test id="test_text3"><placeholder-dont-move/>
+<placeholder-dont-move/><![CDATA[
+]]>
+ </test>
+
+ <test id="test_cdata1">
+ <![CDATA[ ]]><placeholder-dont-move/> <placeholder-dont-move/>
+ </test>
+ <test id="test_cdata2">
+ <![CDATA[ ]]>
+ <![CDATA[ ]]>
+ </test>
+ <test id="test_cdata3">
+ <![CDATA[ ]]>
+ <![CDATA[ ]]>
+ </test>
+ <test id="test_cdata4">
+ <![CDATA[]]>
+ <![CDATA[
+]]>
+ </test>
+ <test id="test_cdata5">
+ <![CDATA[ ]]>
+ <![CDATA[
+]]>
+ </test>
+
+ </test>
+
+ <test id="test_namespaces">
+ <test id="test_ns1">
+ <foo xmlns:quiz="http://example.com/"
+ quiz:q="fun"/>
+ <foo xmlns:f="http://example.com/"
+ f:q="fun"/>
+ </test>
+ <test id="test_ns2">
+ <quiz:foo xmlns:quiz="http://example.com/"
+ q="fun"/>
+ <f:foo xmlns:f="http://example.com/"
+ q="fun"/>
+ </test>
+ </test>
+
+</root>
diff --git a/dom/base/test/unit/nodelist_data_1.xml b/dom/base/test/unit/nodelist_data_1.xml
new file mode 100644
index 0000000000..ddde596a27
--- /dev/null
+++ b/dom/base/test/unit/nodelist_data_1.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" ?>
+<!DOCTYPE Test [
+ <!ATTLIST test id ID #REQUIRED>
+ <!ATTLIST foo:test id ID #REQUIRED>
+ <!ATTLIST foo2:test id ID #REQUIRED>
+ <!ATTLIST bar:test id ID #REQUIRED>
+]>
+
+<!-- Comment -->
+
+<?This-is-a-PI ?>
+
+<root xmlns:foo="foo"
+ xmlns:bar="bar"
+ xmlns:foo2="foo">
+
+ <test id="test1">
+ </test>
+
+ <test id="test2">
+ <!-- Another comment -->
+ <test id="test3">
+ </test>
+
+ <test id="test4" xmlns="foo">
+ <test id="test5">
+ </test>
+
+ <bar:test id="test6" />
+ </test>
+
+ <foo:test id="test7">
+ </foo:test>
+
+ <foo2:test id="test8">
+ <?Another-PI ?>
+ <baz />
+ </foo2:test>
+
+ <bar:test id="test9">
+ </bar:test>
+ </test>
+
+ <foo:test id="test10">
+ <foo2:test id="test11">
+ <bar:test id="test12">
+ </bar:test>
+ </foo2:test>
+ </foo:test>
+
+ <foo2:test id="test13">
+ </foo2:test>
+
+ <bar:test id="test14">
+ </bar:test>
+
+</root>
+
diff --git a/dom/base/test/unit/nodelist_data_2.xhtml b/dom/base/test/unit/nodelist_data_2.xhtml
new file mode 100644
index 0000000000..247ef0353c
--- /dev/null
+++ b/dom/base/test/unit/nodelist_data_2.xhtml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!DOCTYPE window [
+ <!ENTITY fooSet '
+ <addOrRemove foo:foo="foo"/>
+ <addOrRemove foo:foo="bar"/>
+ <addOrRemove foo:bar="foo"/>
+ <addOrRemove foo:bar="bar"/>
+ <addOrRemove foo:foo="foo" foo:bar="bar"/>
+ <addOrRemove foo2:foo="foo"/>
+ <addOrRemove foo="foo"/>
+ <addOrRemove foo="bar"/>
+ <addOrRemove bar="bar" foo="foo"/>
+'>
+]>
+<window
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:foo="foo"
+ xmlns:foo2="foo"
+ xmlns:bar="bar"
+ >
+ <vbox id="boxes">
+ <groupbox id="master1" foo:foo="bar">
+ &fooSet;
+ <groupbox foo:foo="foo">
+ &fooSet;
+ </groupbox>
+ </groupbox>
+ <groupbox id="master2" foo:foo="foo">
+ &fooSet;
+ <groupbox foo:foo="bar">
+ &fooSet;
+ </groupbox>
+ </groupbox>
+ <groupbox id="master3">
+ &fooSet;
+ <groupbox foo2:foo="foo">
+ &fooSet;
+ </groupbox>
+ </groupbox>
+ <groupbox id="external">
+ &fooSet;
+ </groupbox>
+ </vbox>
+</window>
diff --git a/dom/base/test/unit/test_blockParsing.js b/dom/base/test/unit/test_blockParsing.js
new file mode 100644
index 0000000000..cdc4f852e1
--- /dev/null
+++ b/dom/base/test/unit/test_blockParsing.js
@@ -0,0 +1,113 @@
+"use strict";
+
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+const { XPCShellContentUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/XPCShellContentUtils.sys.mjs"
+);
+const { setTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+XPCShellContentUtils.init(this);
+
+function delay() {
+ return new Promise(resolve => {
+ setTimeout(resolve, 0);
+ });
+}
+
+const server = XPCShellContentUtils.createHttpServer({
+ hosts: ["example.com"],
+});
+
+// XML document with only a <script> tag as the document element.
+const PAGE_URL = "http://example.com/";
+server.registerPathHandler("/", (request, response) => {
+ response.setHeader("Content-Type", "application/xhtml+xml");
+ response.write(String.raw`<!DOCTYPE html>
+ <script xmlns="http://www.w3.org/1999/xhtml" src="slow.js"/>
+ `);
+});
+
+let resolveResumeScriptPromise;
+let resumeScriptPromise = new Promise(resolve => {
+ resolveResumeScriptPromise = resolve;
+});
+
+let resolveScriptRequestPromise;
+let scriptRequestPromise = new Promise(resolve => {
+ resolveScriptRequestPromise = resolve;
+});
+
+// An empty script which waits to complete until `resumeScriptPromise`
+// resolves.
+server.registerPathHandler("/slow.js", async (request, response) => {
+ response.processAsync();
+ resolveScriptRequestPromise();
+
+ await resumeScriptPromise;
+
+ response.setHeader("Content-type", "text/javascript");
+ response.write("");
+ response.finish();
+});
+
+// Tests that attempting to block parsing for a <script> tag while the
+// parser is already blocked is handled correctly, and does not cause
+// crashes or hangs.
+add_task(async function test_nested_blockParser() {
+ // Wait for the document element of the page to be inserted, and block
+ // the parser when it is.
+ let resolveBlockerPromise;
+ let blockerPromise;
+ let docElementPromise = TestUtils.topicObserved(
+ "document-element-inserted",
+ doc => {
+ if (doc.location.href === PAGE_URL) {
+ blockerPromise = new Promise(resolve => {
+ resolveBlockerPromise = resolve;
+ });
+
+ doc.blockParsing(blockerPromise);
+ return true;
+ }
+ return false;
+ }
+ );
+
+ // Begin loading the page.
+ let pagePromise = XPCShellContentUtils.loadContentPage(PAGE_URL, {
+ remote: false,
+ });
+
+ // Wait for the document element to be inserted.
+ await docElementPromise;
+ // Wait for the /slow.js script request to initiate.
+ await scriptRequestPromise;
+
+ // Make some trips through the event loop to be safe.
+ await delay();
+ await delay();
+
+ // Allow the /slow.js script request to complete.
+ resolveResumeScriptPromise();
+
+ // Make some trips through the event loop so that the <script> request
+ // unblocks the parser.
+ await delay();
+ await delay();
+
+ // Release the parser blocker added in the observer above.
+ resolveBlockerPromise();
+
+ // Make some trips through the event loop to allow the parser to
+ // unblock.
+ await delay();
+ await delay();
+
+ // Wait for the document to finish loading, and then close it.
+ let page = await pagePromise;
+ await page.close();
+});
diff --git a/dom/base/test/unit/test_bug553888.js b/dom/base/test/unit/test_bug553888.js
new file mode 100644
index 0000000000..b136660ab5
--- /dev/null
+++ b/dom/base/test/unit/test_bug553888.js
@@ -0,0 +1,57 @@
+/* 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/. */
+
+var { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
+
+var server = new HttpServer();
+server.start(-1);
+
+const SERVER_PORT = server.identity.primaryPort;
+const HTTP_BASE = "http://localhost:" + SERVER_PORT;
+const redirectPath = "/redirect";
+const headerCheckPath = "/headerCheck";
+const redirectURL = HTTP_BASE + redirectPath;
+const headerCheckURL = HTTP_BASE + headerCheckPath;
+
+function redirectHandler(metadata, response) {
+ response.setStatusLine(metadata.httpVersion, 302, "Found");
+ response.setHeader("Location", headerCheckURL, false);
+}
+
+function headerCheckHandler(metadata, response) {
+ try {
+ let headerValue = metadata.getHeader("X-Custom-Header");
+ Assert.equal(headerValue, "present");
+ } catch (e) {
+ do_throw("No header present after redirect");
+ }
+ try {
+ metadata.getHeader("X-Unwanted-Header");
+ do_throw("Unwanted header present after redirect");
+ } catch (x) {}
+ response.setStatusLine(metadata.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "text/plain");
+ response.write("");
+}
+
+function run_test() {
+ server.registerPathHandler(redirectPath, redirectHandler);
+ server.registerPathHandler(headerCheckPath, headerCheckHandler);
+
+ do_test_pending();
+ var request = new XMLHttpRequest();
+ request.open("GET", redirectURL, true);
+ request.setRequestHeader("X-Custom-Header", "present");
+ request.addEventListener("readystatechange", function () {
+ if (request.readyState == 4) {
+ Assert.equal(request.status, 200);
+ server.stop(do_test_finished);
+ }
+ });
+ request.send();
+ try {
+ request.setRequestHeader("X-Unwanted-Header", "present");
+ do_throw("Shouldn't be able to set a header after send");
+ } catch (x) {}
+}
diff --git a/dom/base/test/unit/test_bug737966.js b/dom/base/test/unit/test_bug737966.js
new file mode 100644
index 0000000000..a5b8f48425
--- /dev/null
+++ b/dom/base/test/unit/test_bug737966.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* If charset parameter is invalid, the encoding should be detected as UTF-8 */
+
+function run_test() {
+ let body = '<?xml version="1.0"><html>%c3%80</html>';
+ let result = '<?xml version="1.0"><html>\u00c0</html>';
+
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", "data:text/xml;charset=abc," + body, false);
+ xhr.send(null);
+
+ Assert.equal(xhr.responseText, result);
+}
diff --git a/dom/base/test/unit/test_cancelPrefetch.js b/dom/base/test/unit/test_cancelPrefetch.js
new file mode 100644
index 0000000000..6663d60fbb
--- /dev/null
+++ b/dom/base/test/unit/test_cancelPrefetch.js
@@ -0,0 +1,149 @@
+var prefetch = Cc["@mozilla.org/prefetch-service;1"].getService(
+ Ci.nsIPrefetchService
+);
+
+var ReferrerInfo = Components.Constructor(
+ "@mozilla.org/referrer-info;1",
+ "nsIReferrerInfo",
+ "init"
+);
+
+var ios = Services.io;
+var prefs = Services.prefs;
+
+var parser = new DOMParser();
+
+var doc;
+
+var docbody =
+ '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' +
+ '<link id="node1"/><link id="node2"/>' +
+ "</body></html>";
+
+var node1;
+var node2;
+
+function run_test() {
+ prefs.setBoolPref("network.prefetch-next", true);
+
+ doc = parser.parseFromString(docbody, "text/html");
+
+ node1 = doc.getElementById("node1");
+ node2 = doc.getElementById("node2");
+
+ run_next_test();
+}
+
+add_test(function test_cancel1() {
+ var uri = ios.newURI("http://localhost/1");
+ var referrerInfo = new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, uri);
+
+ prefetch.prefetchURI(uri, referrerInfo, node1, true);
+
+ Assert.ok(prefetch.hasMoreElements(), "There is a request in the queue");
+
+ // Trying to prefetch again the same uri with the same node will fail.
+ var didFail = 0;
+
+ try {
+ prefetch.prefetchURI(uri, referrerInfo, node1, true);
+ } catch (e) {
+ didFail = 1;
+ }
+
+ Assert.ok(
+ didFail == 1,
+ "Prefetching the same request with the same node fails."
+ );
+
+ Assert.ok(prefetch.hasMoreElements(), "There is still request in the queue");
+
+ prefetch.cancelPrefetchPreloadURI(uri, node1);
+
+ Assert.ok(!prefetch.hasMoreElements(), "There is no request in the queue");
+ run_next_test();
+});
+
+add_test(function test_cancel2() {
+ // Prefetch a uri with 2 different nodes. There should be 2 request
+ // in the queue and canceling one will not cancel the other.
+
+ var uri = ios.newURI("http://localhost/1");
+ var referrerInfo = new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, uri);
+
+ prefetch.prefetchURI(uri, referrerInfo, node1, true);
+ prefetch.prefetchURI(uri, referrerInfo, node2, true);
+
+ Assert.ok(prefetch.hasMoreElements(), "There are requests in the queue");
+
+ prefetch.cancelPrefetchPreloadURI(uri, node1);
+
+ Assert.ok(
+ prefetch.hasMoreElements(),
+ "There is still one more request in the queue"
+ );
+
+ prefetch.cancelPrefetchPreloadURI(uri, node2);
+
+ Assert.ok(!prefetch.hasMoreElements(), "There is no request in the queue");
+ run_next_test();
+});
+
+add_test(function test_cancel3() {
+ // Request a prefetch of a uri. Trying to cancel a prefetch for the same uri
+ // with a different node will fail.
+ var uri = ios.newURI("http://localhost/1");
+ var referrerInfo = new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, uri);
+
+ prefetch.prefetchURI(uri, referrerInfo, node1, true);
+
+ Assert.ok(prefetch.hasMoreElements(), "There is a request in the queue");
+
+ var didFail = 0;
+
+ try {
+ prefetch.cancelPrefetchPreloadURI(uri, node2, true);
+ } catch (e) {
+ didFail = 1;
+ }
+ Assert.ok(didFail == 1, "Canceling the request failed");
+
+ Assert.ok(
+ prefetch.hasMoreElements(),
+ "There is still a request in the queue"
+ );
+
+ prefetch.cancelPrefetchPreloadURI(uri, node1);
+ Assert.ok(!prefetch.hasMoreElements(), "There is no request in the queue");
+ run_next_test();
+});
+
+add_test(function test_cancel4() {
+ // Request a prefetch of a uri. Trying to cancel a prefetch for a different uri
+ // with the same node will fail.
+ var uri1 = ios.newURI("http://localhost/1");
+ var uri2 = ios.newURI("http://localhost/2");
+ var referrerInfo = new ReferrerInfo(Ci.nsIReferrerInfo.EMPTY, true, uri1);
+
+ prefetch.prefetchURI(uri1, referrerInfo, node1, true);
+
+ Assert.ok(prefetch.hasMoreElements(), "There is a request in the queue");
+
+ var didFail = 0;
+
+ try {
+ prefetch.cancelPrefetchPreloadURI(uri2, node1);
+ } catch (e) {
+ didFail = 1;
+ }
+ Assert.ok(didFail == 1, "Canceling the request failed");
+
+ Assert.ok(
+ prefetch.hasMoreElements(),
+ "There is still a request in the queue"
+ );
+
+ prefetch.cancelPrefetchPreloadURI(uri1, node1);
+ Assert.ok(!prefetch.hasMoreElements(), "There is no request in the queue");
+ run_next_test();
+});
diff --git a/dom/base/test/unit/test_chromeutils_base64.js b/dom/base/test/unit/test_chromeutils_base64.js
new file mode 100644
index 0000000000..ca2722016b
--- /dev/null
+++ b/dom/base/test/unit/test_chromeutils_base64.js
@@ -0,0 +1,140 @@
+"use strict";
+
+function run_test() {
+ test_base64URLEncode();
+ test_base64URLDecode();
+}
+
+// Test vectors from RFC 4648, section 10.
+let textTests = {
+ "": "",
+ f: "Zg",
+ fo: "Zm8",
+ foo: "Zm9v",
+ foob: "Zm9vYg",
+ fooba: "Zm9vYmE",
+ foobar: "Zm9vYmFy",
+};
+
+// Examples from RFC 4648, section 9.
+let binaryTests = [
+ {
+ decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]),
+ encoded: "FPucA9l-",
+ },
+ {
+ decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03, 0xd9]),
+ encoded: "FPucA9k",
+ },
+ {
+ decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03]),
+ encoded: "FPucAw",
+ },
+];
+
+function padEncodedValue(value) {
+ switch (value.length % 4) {
+ case 0:
+ return value;
+ case 2:
+ return value + "==";
+ case 3:
+ return value + "=";
+ default:
+ throw new TypeError("Invalid encoded value");
+ }
+}
+
+function testEncode(input, encoded) {
+ equal(
+ ChromeUtils.base64URLEncode(input, { pad: false }),
+ encoded,
+ encoded + " without padding"
+ );
+ equal(
+ ChromeUtils.base64URLEncode(input, { pad: true }),
+ padEncodedValue(encoded),
+ encoded + " with padding"
+ );
+}
+
+function test_base64URLEncode() {
+ throws(
+ _ => ChromeUtils.base64URLEncode(new Uint8Array(0)),
+ /TypeError/,
+ "Should require encoding options"
+ );
+ throws(
+ _ => ChromeUtils.base64URLEncode(new Uint8Array(0), {}),
+ /TypeError/,
+ "Encoding should require the padding option"
+ );
+
+ for (let { decoded, encoded } of binaryTests) {
+ testEncode(decoded, encoded);
+ }
+
+ let textEncoder = new TextEncoder();
+ for (let decoded of Object.keys(textTests)) {
+ let input = textEncoder.encode(decoded);
+ testEncode(input, textTests[decoded]);
+ }
+}
+
+function testDecode(input, decoded) {
+ let buffer = ChromeUtils.base64URLDecode(input, { padding: "reject" });
+ deepEqual(new Uint8Array(buffer), decoded, input + " with padding rejected");
+
+ let paddedValue = padEncodedValue(input);
+ buffer = ChromeUtils.base64URLDecode(paddedValue, { padding: "ignore" });
+ deepEqual(new Uint8Array(buffer), decoded, input + " with padding ignored");
+
+ if (paddedValue.length > input.length) {
+ throws(
+ _ => ChromeUtils.base64URLDecode(paddedValue, { padding: "reject" }),
+ /NS_ERROR_ILLEGAL_VALUE/,
+ paddedValue + " with padding rejected should throw"
+ );
+
+ throws(
+ _ => ChromeUtils.base64URLDecode(input, { padding: "require" }),
+ /NS_ERROR_ILLEGAL_VALUE/,
+ input + " with padding required should throw"
+ );
+
+ buffer = ChromeUtils.base64URLDecode(paddedValue, { padding: "require" });
+ deepEqual(
+ new Uint8Array(buffer),
+ decoded,
+ paddedValue + " with padding required"
+ );
+ }
+}
+
+function test_base64URLDecode() {
+ throws(
+ _ => ChromeUtils.base64URLDecode(""),
+ /TypeError/,
+ "Should require decoding options"
+ );
+ throws(
+ _ => ChromeUtils.base64URLDecode("", {}),
+ /TypeError/,
+ "Decoding should require the padding option"
+ );
+ throws(
+ _ => ChromeUtils.base64URLDecode("", { padding: "chocolate" }),
+ /TypeError/,
+ "Decoding should throw for invalid padding policy"
+ );
+
+ for (let { decoded, encoded } of binaryTests) {
+ testDecode(encoded, decoded);
+ }
+
+ let textEncoder = new TextEncoder();
+ for (let decoded of Object.keys(textTests)) {
+ let expectedBuffer = textEncoder.encode(decoded);
+ testDecode(textTests[decoded], expectedBuffer);
+ }
+}
diff --git a/dom/base/test/unit/test_chromeutils_getXPCOMErrorName.js b/dom/base/test/unit/test_chromeutils_getXPCOMErrorName.js
new file mode 100644
index 0000000000..f7d6a89e71
--- /dev/null
+++ b/dom/base/test/unit/test_chromeutils_getXPCOMErrorName.js
@@ -0,0 +1,40 @@
+"use strict";
+
+// Test ChromeUtils.getXPCOMErrorName
+
+add_task(function test_getXPCOMErrorName() {
+ info("Force the initialization of NSS to get the error names right");
+ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+
+ Assert.equal(
+ ChromeUtils.getXPCOMErrorName(Cr.NS_OK),
+ "NS_OK",
+ "getXPCOMErrorName works for NS_OK"
+ );
+
+ Assert.equal(
+ ChromeUtils.getXPCOMErrorName(Cr.NS_ERROR_FAILURE),
+ "NS_ERROR_FAILURE",
+ "getXPCOMErrorName works for NS_ERROR_FAILURE"
+ );
+
+ const nssErrors = Cc["@mozilla.org/nss_errors_service;1"].getService(
+ Ci.nsINSSErrorsService
+ );
+ Assert.equal(
+ ChromeUtils.getXPCOMErrorName(
+ nssErrors.getXPCOMFromNSSError(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)
+ ),
+ "NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, SEC_ERROR_IO)",
+ "getXPCOMErrorName works for NSS_SEC_ERROR_BASE"
+ );
+ // See https://searchfox.org/mozilla-central/rev/a48e21143960b383004afa9ff9411c5cf6d5a958/security/nss/lib/util/secerr.h#20
+ const SEC_ERROR_BAD_DATA = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE + 2;
+ Assert.equal(
+ ChromeUtils.getXPCOMErrorName(
+ nssErrors.getXPCOMFromNSSError(SEC_ERROR_BAD_DATA)
+ ),
+ "NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, SEC_ERROR_BAD_DATA)",
+ "getXPCOMErrorName works for NSS's SEC_ERROR_BAD_DATA"
+ );
+});
diff --git a/dom/base/test/unit/test_chromeutils_shallowclone.js b/dom/base/test/unit/test_chromeutils_shallowclone.js
new file mode 100644
index 0000000000..03e0d443c9
--- /dev/null
+++ b/dom/base/test/unit/test_chromeutils_shallowclone.js
@@ -0,0 +1,60 @@
+"use strict";
+
+add_task(function test_shallowclone() {
+ // Check that shallow cloning an object with regular properties,
+ // results into a new object with all properties from the source object.
+ const fullyCloneableObject = {
+ numProp: 123,
+ strProp: "str",
+ boolProp: true,
+ arrayProp: [{ item1: "1", item2: "2" }],
+ fnProp() {
+ return "fn result";
+ },
+ promise: Promise.resolve("promised-value"),
+ weakmap: new WeakMap(),
+ proxy: new Proxy({}, {}),
+ };
+
+ let clonedObject = ChromeUtils.shallowClone(fullyCloneableObject);
+
+ Assert.deepEqual(
+ clonedObject,
+ fullyCloneableObject,
+ "Got the expected cloned object for an object with regular properties"
+ );
+
+ // Check that shallow cloning an object with getters and setters properties,
+ // results into a new object without all the properties from the source object excluded
+ // its getters and setters.
+ const objectWithGetterAndSetter = {
+ get myGetter() {
+ return "getter result";
+ },
+ set mySetter(v) {},
+ myFunction() {
+ return "myFunction result";
+ },
+ };
+
+ clonedObject = ChromeUtils.shallowClone(objectWithGetterAndSetter);
+
+ Assert.deepEqual(
+ clonedObject,
+ {
+ myFunction: objectWithGetterAndSetter.myFunction,
+ },
+ "Got the expected cloned object for an object with getters and setters"
+ );
+
+ // Check that shallow cloning a proxy object raises the expected exception..
+ const proxyObject = new Proxy(fullyCloneableObject, {});
+
+ Assert.throws(
+ () => {
+ ChromeUtils.shallowClone(proxyObject);
+ },
+ /Shallow cloning a proxy object is not allowed/,
+ "Got the expected error on ChromeUtils.shallowClone called on a proxy object"
+ );
+});
diff --git a/dom/base/test/unit/test_delete_range.xml b/dom/base/test/unit/test_delete_range.xml
new file mode 100644
index 0000000000..c8d50bd32a
--- /dev/null
+++ b/dom/base/test/unit/test_delete_range.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+This file holds serialized tests for DOM Range tests on extractContents.
+The <test/> elements designate individual tests. Each one has the following:
+
+* A <source/> element, designating the start conditions of the test,
+* A <result/> element, designating what the source element should look like
+ after the extraction,
+* An <extract/> element, designating what the extracted content should look like.
+
+The <split/> element designates a split between two DOM nodes. This element will
+be removed before the actual test, and the two nodes on either side will not be
+merged.
+
+The <empty-cdata/> element designates an empty character data section. Before
+the test executes, this element is replaced with an actual CDATASection node.
+
+For the <source/> element, there are four attributes:
+
+* startContainer: A XPath to the startContainer of the range.
+* endContainer: A XPath to the endContainer of the range.
+* startOffset: The startOffset of the range.
+* endOffset: The endOffset of the range.
+
+Note this test may need updating with a fix for bug 401276. The spec states
+adjacent nodes after an extraction should be merged if possible, but using the
+normalize() method, which could have unintended side effects... For now, we're
+not permitting that, pending clarification.
+
+Please make sure the first test in this document always tests a range where the
+start container and end container are the same text node, and where the start
+offset and end offsets are valid and inequal. Some of the additional range
+tests (after the bulk of the delete/extract tests) depend on it.
+ -->
+<root>
+ <!-- Extracting from a text node. -->
+ <test>
+ <source startContainer="text()[1]"
+ endContainer="text()[1]"
+ startOffset="4"
+ endOffset="10">The quick fox</source>
+ <result>The fox</result>
+ <extract>quick </extract>
+ </test>
+
+ <!-- Extracting from a CDATA section. -->
+ <test>
+ <source startContainer="text()[1]"
+ endContainer="text()[1]"
+ startOffset="4"
+ endOffset="10"><![CDATA[The quick fox]]></source>
+ <result><![CDATA[The fox]]></result>
+ <extract><![CDATA[quick ]]></extract>
+ </test>
+
+ <!-- Snipping the start of a text node. -->
+ <test>
+ <source startContainer="text()[1]"
+ endContainer="text()[1]"
+ startOffset="0"
+ endOffset="4"><![CDATA[The quick fox]]></source>
+ <result><![CDATA[quick fox]]></result>
+ <extract><![CDATA[The ]]></extract>
+ </test>
+
+ <!-- Extracting from a comment. -->
+ <test>
+ <source startContainer="comment()[1]"
+ endContainer="comment()[1]"
+ startOffset="4"
+ endOffset="10"><!--The quick fox--></source>
+ <result><!--The fox--></result>
+ <extract><!--quick --></extract>
+ </test>
+
+ <!-- Snipping whole nodes -->
+ <test>
+ <source startContainer="."
+ endContainer="."
+ startOffset="0"
+ endOffset="2">Fox<fox/>Fox<bear/><!--comment--></source>
+ <result>Fox<bear/><!--comment--></result>
+ <extract>Fox<fox/></extract>
+ </test>
+
+ <!-- Snipping whole nodes -->
+ <test>
+ <source startContainer="."
+ endContainer="."
+ startOffset="1"
+ endOffset="3">Fox<fox/>Fox<bear/><!--comment--></source>
+ <result>Fox<bear/><!--comment--></result>
+ <extract><fox/>Fox</extract>
+ </test>
+
+ <!-- Snipping a mixture of nodes and portions of text -->
+ <test>
+ <source startContainer="text()[2]"
+ startOffset="1"
+ endContainer="comment()[1]"
+ endOffset="3">Fox<fox/>Fox<bear><?cow ?></bear><!--comment--></source>
+ <result>Fox<fox/>F<!--ment--></result>
+ <extract>ox<bear><?cow ?></bear><!--com--></extract>
+ </test>
+
+ <!-- Extracting with a collapsed range from a text node. -->
+ <test>
+ <source startContainer="text()[1]"
+ endContainer="text()[1]"
+ startOffset="4"
+ endOffset="4">The quick fox</source>
+ <result>The quick fox</result>
+ <extract/>
+ </test>
+
+ <!-- Extracting with a collapsed range from a non-text node. -->
+ <test>
+ <source startContainer="."
+ endContainer="."
+ startOffset="0"
+ endOffset="0">Fox<fox/>Fox<bear/><!--comment--></source>
+ <result>Fox<fox/>Fox<bear/><!--comment--></result>
+ <extract/>
+ </test>
+</root>
diff --git a/dom/base/test/unit/test_error_codes.js b/dom/base/test/unit/test_error_codes.js
new file mode 100644
index 0000000000..72b9e371d1
--- /dev/null
+++ b/dom/base/test/unit/test_error_codes.js
@@ -0,0 +1,64 @@
+/* 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/.
+ */
+
+var gExpectedStatus = null;
+var gNextTestFunc = null;
+
+var prefs = Services.prefs;
+
+var asyncXHR = {
+ load() {
+ var request = new XMLHttpRequest();
+ request.open("GET", "http://localhost:4444/test_error_code.xml", true);
+
+ var self = this;
+ request.addEventListener("error", function (event) {
+ self.onError(event);
+ });
+ request.send(null);
+ },
+ onError: function doAsyncRequest_onError(event) {
+ var request = event.target.channel.QueryInterface(Ci.nsIRequest);
+ Assert.equal(request.status, gExpectedStatus);
+ gNextTestFunc();
+ },
+};
+
+function run_test() {
+ do_test_pending();
+ do_timeout(0, run_test_pt1);
+}
+
+// network offline
+function run_test_pt1() {
+ try {
+ Services.io.manageOfflineStatus = false;
+ } catch (e) {}
+ Services.io.offline = true;
+ prefs.setBoolPref("network.dns.offline-localhost", false);
+ // We always resolve localhost as it's hardcoded without the following pref:
+ prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true);
+
+ gExpectedStatus = Cr.NS_ERROR_OFFLINE;
+ gNextTestFunc = run_test_pt2;
+ dump("Testing error returned by async XHR when the network is offline\n");
+ asyncXHR.load();
+}
+
+// connection refused
+function run_test_pt2() {
+ Services.io.offline = false;
+ prefs.clearUserPref("network.dns.offline-localhost");
+ prefs.clearUserPref("network.proxy.allow_hijacking_localhost");
+
+ gExpectedStatus = Cr.NS_ERROR_CONNECTION_REFUSED;
+ gNextTestFunc = end_test;
+ dump("Testing error returned by aync XHR when the connection is refused\n");
+ asyncXHR.load();
+}
+
+function end_test() {
+ do_test_finished();
+}
diff --git a/dom/base/test/unit/test_generate_xpath.js b/dom/base/test/unit/test_generate_xpath.js
new file mode 100644
index 0000000000..e8c7043690
--- /dev/null
+++ b/dom/base/test/unit/test_generate_xpath.js
@@ -0,0 +1,85 @@
+function run_test() {
+ test_generate_xpath();
+}
+
+// TEST CODE
+
+function test_generate_xpath() {
+ let docString = `
+ <html>
+ <body>
+ <label><input type="checkbox" id="input1" />Input 1</label>
+ <label><input type="checkbox" id="input2'" />Input 2</label>
+ <label><input type="checkbox" id='"input3"' />Input 3</label>
+ <label><input type="checkbox"/>Input 4</label>
+ <label><input type="checkbox" />Input 5</label>
+ </body>
+ </html>
+ `;
+ let doc = getParser().parseFromString(docString, "text/html");
+
+ // Test generate xpath for body.
+ info("Test generate xpath for body node");
+ let body = doc.getElementsByTagName("body")[0];
+ let bodyXPath = body.generateXPath();
+ let bodyExpXPath = "/xhtml:html/xhtml:body";
+ equal(bodyExpXPath, bodyXPath, " xpath generated for body");
+
+ // Test generate xpath for input with id.
+ info("Test generate xpath for input with id");
+ let inputWithId = doc.getElementById("input1");
+ let inputWithIdXPath = inputWithId.generateXPath();
+ let inputWithIdExpXPath = "//xhtml:input[@id='input1']";
+ equal(
+ inputWithIdExpXPath,
+ inputWithIdXPath,
+ " xpath generated for input with id"
+ );
+
+ // Test generate xpath for input with id has single quote.
+ info("Test generate xpath for input with id has single quote");
+ let inputWithIdSingleQuote = doc.getElementsByTagName("input")[1];
+ let inputWithIdXPathSingleQuote = inputWithIdSingleQuote.generateXPath();
+ let inputWithIdExpXPathSingleQuote = '//xhtml:input[@id="input2\'"]';
+ equal(
+ inputWithIdExpXPathSingleQuote,
+ inputWithIdXPathSingleQuote,
+ " xpath generated for input with id"
+ );
+
+ // Test generate xpath for input with id has double quote.
+ info("Test generate xpath for input with id has double quote");
+ let inputWithIdDoubleQuote = doc.getElementsByTagName("input")[2];
+ let inputWithIdXPathDoubleQuote = inputWithIdDoubleQuote.generateXPath();
+ let inputWithIdExpXPathDoubleQuote = "//xhtml:input[@id='\"input3\"']";
+ equal(
+ inputWithIdExpXPathDoubleQuote,
+ inputWithIdXPathDoubleQuote,
+ " xpath generated for input with id"
+ );
+
+ // Test generate xpath for input with id has both single and double quote.
+ info("Test generate xpath for input with id has single and double quote");
+ let inputWithIdSingleDoubleQuote = doc.getElementsByTagName("input")[3];
+ inputWithIdSingleDoubleQuote.setAttribute("id", "\"input'4");
+ let inputWithIdXPathSingleDoubleQuote =
+ inputWithIdSingleDoubleQuote.generateXPath();
+ let inputWithIdExpXPathSingleDoubleQuote =
+ "//xhtml:input[@id=concat('\"input',\"'\",'4')]";
+ equal(
+ inputWithIdExpXPathSingleDoubleQuote,
+ inputWithIdXPathSingleDoubleQuote,
+ " xpath generated for input with id"
+ );
+
+ // Test generate xpath for input without id.
+ info("Test generate xpath for input without id");
+ let inputNoId = doc.getElementsByTagName("input")[4];
+ let inputNoIdXPath = inputNoId.generateXPath();
+ let inputNoIdExpXPath = "/xhtml:html/xhtml:body/xhtml:label[5]/xhtml:input";
+ equal(
+ inputNoIdExpXPath,
+ inputNoIdXPath,
+ " xpath generated for input without id"
+ );
+}
diff --git a/dom/base/test/unit/test_htmlserializer.js b/dom/base/test/unit/test_htmlserializer.js
new file mode 100644
index 0000000000..17995dddde
--- /dev/null
+++ b/dom/base/test/unit/test_htmlserializer.js
@@ -0,0 +1,70 @@
+/* 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/. */
+
+add_task(async function testAttrsOutsideBodyWithRawBodyOnly() {
+ // Create a simple HTML document in which the header contains a tag with set
+ // attributes
+ const htmlString = `<html><head><link rel="stylesheet" href="foo"/></head><body>some content</body></html>`;
+
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(htmlString, "text/html");
+
+ // Sanity check
+ const linkElems = doc.head.getElementsByTagName("link");
+ Assert.equal(
+ linkElems.length,
+ 1,
+ "document header should contain one link element"
+ );
+ Assert.equal(
+ linkElems[0].rel,
+ "stylesheet",
+ "link element should have rel attribute set"
+ );
+
+ // Verify that the combination of raw output and body-only does not allow
+ // attributes from header elements to creep into the output string
+ const encoder = Cu.createDocumentEncoder("text/html");
+ encoder.init(
+ doc,
+ "text/html",
+ Ci.nsIDocumentEncoder.OutputRaw | Ci.nsIDocumentEncoder.OutputBodyOnly
+ );
+
+ const result = encoder.encodeToString();
+ Assert.equal(
+ result,
+ "<body>some content</body>",
+ "output should not contain attributes from head elements"
+ );
+});
+
+add_task(async function testAttrsInsideBodyWithRawBodyOnly() {
+ // Create a simple HTML document in which the body contains a tag with set
+ // attributes
+ const htmlString = `<html><head><link rel="stylesheet" href="foo"/></head><body><span id="foo">some content</span></body></html>`;
+
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(htmlString, "text/html");
+
+ // Sanity check
+ const spanElem = doc.getElementById("foo");
+ Assert.ok(spanElem, "should be able to get span element by ID");
+
+ // Verify that the combination of raw output and body-only does not strip
+ // tag attributes inside the body
+ const encoder = Cu.createDocumentEncoder("text/html");
+ encoder.init(
+ doc,
+ "text/html",
+ Ci.nsIDocumentEncoder.OutputRaw | Ci.nsIDocumentEncoder.OutputBodyOnly
+ );
+
+ const result = encoder.encodeToString();
+ Assert.equal(
+ result,
+ `<body><span id="foo">some content</span></body>`,
+ "output should not contain attributes from head elements"
+ );
+});
diff --git a/dom/base/test/unit/test_isequalnode.js b/dom/base/test/unit/test_isequalnode.js
new file mode 100644
index 0000000000..1b9491fcdc
--- /dev/null
+++ b/dom/base/test/unit/test_isequalnode.js
@@ -0,0 +1,390 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// TEST CODE
+
+var doc; // cache for use in all tests
+
+add_setup(function init() {
+ doc = ParseFile("isequalnode_data.xml");
+});
+
+add_task(function test_isEqualNode_setAttribute() {
+ // NOTE: 0, 2 are whitespace
+ var test1 = doc.getElementById("test_setAttribute");
+ var node1 = test1.childNodes.item(1);
+ var node2 = test1.childNodes.item(3);
+
+ check_eq_nodes(node1, node2);
+
+ node1.setAttribute("bar", "baz");
+ check_neq_nodes(node1, node2);
+
+ node2.setAttribute("bar", "baz");
+ check_eq_nodes(node1, node2);
+
+ // the null namespace is equivalent to no namespace -- section 1.3.3
+ // (XML Namespaces) of DOM 3 Core
+ node1.setAttributeNS(null, "quux", "17");
+ check_neq_nodes(node1, node2);
+
+ node2.setAttribute("quux", "17");
+ check_eq_nodes(node1, node2);
+
+ node2.setAttributeNS("http://mozilla.org/", "seamonkey", "rheet");
+ check_neq_nodes(node1, node2);
+
+ node1.setAttribute("seamonkey", "rheet");
+ check_neq_nodes(node1, node2);
+
+ node1.setAttributeNS("http://mozilla.org/", "seamonkey", "rheet");
+ check_neq_nodes(node1, node2);
+
+ // this overwrites the namespaced "seamonkey" attribute added to node2
+ // earlier, because this simply sets whatever attribute has the fully
+ // qualified name "seamonkey" (the setAttributeNS attribute string wasn't
+ // prefixed) -- consequently, node1 and node2 are still unequal
+ node2.setAttribute("seamonkey", "rheet");
+ check_neq_nodes(node1, node2);
+});
+
+add_task(function test_isEqualNode_clones() {
+ // tests all elements and attributes in the document
+ var all_elts = doc.getElementsByTagName("*");
+ for (var i = 0; i < all_elts.length; i++) {
+ var elt = all_elts.item(i);
+ check_eq_nodes(elt, elt.cloneNode(true));
+
+ var attrs = elt.attributes;
+ for (var j = 0; j < attrs.length; j++) {
+ var attr = attrs.item(j);
+ check_eq_nodes(attr, attr.cloneNode(true));
+ }
+ }
+
+ var elm = doc.createElement("foo");
+ check_eq_nodes(elm, elm.cloneNode(true));
+ check_eq_nodes(elm, elm.cloneNode(false));
+
+ elm.setAttribute("fiz", "eit");
+ check_eq_nodes(elm, elm.cloneNode(true));
+ check_eq_nodes(elm, elm.cloneNode(false));
+
+ elm.setAttributeNS("http://example.com/", "trendoid", "arthroscope");
+ check_eq_nodes(elm, elm.cloneNode(true));
+ check_eq_nodes(elm, elm.cloneNode(false));
+
+ var elm2 = elm.cloneNode(true);
+ check_eq_nodes(elm, elm2);
+
+ const TEXT = "fetishist";
+
+ elm.textContent = TEXT;
+ check_neq_nodes(elm, elm2);
+
+ check_neq_nodes(elm, elm.cloneNode(false));
+ check_eq_nodes(elm, elm.cloneNode(true));
+
+ elm2.appendChild(doc.createTextNode(TEXT));
+ check_eq_nodes(elm, elm2);
+
+ var att = doc.createAttribute("bar");
+ check_eq_nodes(att, att.cloneNode(true));
+ check_eq_nodes(att, att.cloneNode(false));
+});
+
+add_task(function test_isEqualNode_variety() {
+ const nodes = [
+ doc.createElement("foo"),
+ doc.createElementNS("http://example.com/", "foo"),
+ doc.createElementNS("http://example.org/", "foo"),
+ doc.createElementNS("http://example.com/", "FOO"),
+ doc.createAttribute("foo", "href='biz'"),
+ doc.createAttributeNS("http://example.com/", "foo", "href='biz'"),
+ doc.createTextNode("foo"),
+ doc.createTextNode(" "),
+ doc.createTextNode(" "),
+ doc.createComment("foo"),
+ doc.createProcessingInstruction("foo", "href='biz'"),
+ doc.implementation.createDocumentType("foo", "href='biz'", ""),
+ doc.implementation.createDocument("http://example.com/", "foo", null),
+ doc.createDocumentFragment(),
+ ];
+
+ for (var i = 0; i < nodes.length; i++) {
+ for (var j = i; j < nodes.length; j++) {
+ if (i == j) {
+ check_eq_nodes(nodes[i], nodes[j]);
+ } else {
+ check_neq_nodes(nodes[i], nodes[j]);
+ }
+ }
+ }
+});
+
+add_task(function test_isEqualNode_normalization() {
+ var norm = doc.getElementById("test_normalization");
+ var node1 = norm.childNodes.item(1);
+ var node2 = norm.childNodes.item(3);
+
+ check_eq_nodes(node1, node2);
+
+ node1.appendChild(doc.createTextNode(""));
+ check_neq_nodes(node1, node2);
+
+ node1.normalize();
+ check_eq_nodes(node1, node2);
+
+ node2.appendChild(doc.createTextNode("fun"));
+ node2.appendChild(doc.createTextNode("ctor"));
+ node1.appendChild(doc.createTextNode("functor"));
+ check_neq_nodes(node1, node2);
+
+ node1.normalize();
+ check_neq_nodes(node1, node2);
+
+ node2.normalize();
+ check_eq_nodes(node1, node2);
+
+ // reset
+ while (node1.hasChildNodes()) {
+ node1.removeChild(node1.childNodes.item(0));
+ }
+ while (node2.hasChildNodes()) {
+ node2.removeChild(node2.childNodes.item(0));
+ }
+
+ // attribute normalization testing
+
+ var at1 = doc.createAttribute("foo");
+ var at2 = doc.createAttribute("foo");
+ check_eq_nodes(at1, at2);
+
+ // Attr.appendChild isn't implemented yet (bug 56758), so don't run this yet
+ if (false) {
+ at1.appendChild(doc.createTextNode("rasp"));
+ at2.appendChild(doc.createTextNode("rasp"));
+ check_eq_nodes(at1, at2);
+
+ at1.appendChild(doc.createTextNode(""));
+ check_neq_nodes(at1, at2);
+
+ at1.normalize();
+ check_eq_nodes(at1, at2);
+
+ at1.appendChild(doc.createTextNode("berry"));
+ check_neq_nodes(at1, at2);
+
+ at2.appendChild(doc.createTextNode("ber"));
+ check_neq_nodes(at1, at2);
+
+ at2.appendChild(doc.createTextNode("ry"));
+ check_neq_nodes(at1, at2);
+
+ at1.normalize();
+ check_neq_nodes(at1, at2);
+
+ at2.normalize();
+ check_eq_nodes(at1, at2);
+ }
+
+ node1.setAttributeNode(at1);
+ check_neq_nodes(node1, node2);
+
+ node2.setAttributeNode(at2);
+ check_eq_nodes(node1, node2);
+
+ var n1text1 = doc.createTextNode("ratfink");
+ var n1elt = doc.createElement("fruitcake");
+ var n1text2 = doc.createTextNode("hydrospanner");
+
+ node1.appendChild(n1text1);
+ node1.appendChild(n1elt);
+ node1.appendChild(n1text2);
+
+ check_neq_nodes(node1, node2);
+
+ var n2text1a = doc.createTextNode("rat");
+ var n2text1b = doc.createTextNode("fink");
+ var n2elt = doc.createElement("fruitcake");
+ var n2text2 = doc.createTextNode("hydrospanner");
+
+ node2.appendChild(n2text1b);
+ node2.appendChild(n2elt);
+ node2.appendChild(n2text2);
+ check_neq_nodes(node1, node2);
+
+ node2.insertBefore(n2text1a, n2text1b);
+ check_neq_nodes(node1, node2);
+
+ var tmp_node1 = node1.cloneNode(true);
+ tmp_node1.normalize();
+ var tmp_node2 = node2.cloneNode(true);
+ tmp_node2.normalize();
+ check_eq_nodes(tmp_node1, tmp_node2);
+
+ n2elt.appendChild(doc.createTextNode(""));
+ check_neq_nodes(node1, node2);
+
+ tmp_node1 = node1.cloneNode(true);
+ tmp_node1.normalize();
+ tmp_node2 = node2.cloneNode(true);
+ tmp_node2.normalize();
+ check_eq_nodes(tmp_node1, tmp_node2);
+
+ var typeText1 = doc.createTextNode("type");
+ n2elt.appendChild(typeText1);
+ tmp_node1 = node1.cloneNode(true);
+ tmp_node1.normalize();
+ tmp_node2 = node2.cloneNode(true);
+ tmp_node2.normalize();
+ check_neq_nodes(tmp_node1, tmp_node2);
+
+ n1elt.appendChild(doc.createTextNode("typedef"));
+ tmp_node1 = node1.cloneNode(true);
+ tmp_node1.normalize();
+ tmp_node2 = node2.cloneNode(true);
+ tmp_node2.normalize();
+ check_neq_nodes(tmp_node1, tmp_node2);
+ check_neq_nodes(n1elt, n2elt);
+
+ var typeText2 = doc.createTextNode("def");
+ n2elt.appendChild(typeText2);
+ tmp_node1 = node1.cloneNode(true);
+ tmp_node1.normalize();
+ tmp_node2 = node2.cloneNode(true);
+ tmp_node2.normalize();
+ check_eq_nodes(tmp_node1, tmp_node2);
+ check_neq_nodes(node1, node2);
+
+ n2elt.insertBefore(doc.createTextNode(""), typeText2);
+ check_neq_nodes(node1, node2);
+
+ n2elt.insertBefore(doc.createTextNode(""), typeText2);
+ check_neq_nodes(node1, node2);
+
+ n2elt.insertBefore(doc.createTextNode(""), typeText1);
+ check_neq_nodes(node1, node2);
+
+ node1.normalize();
+ node2.normalize();
+ check_eq_nodes(node1, node2);
+});
+
+add_task(function test_isEqualNode_whitespace() {
+ equality_check_kids("test_pi1", true);
+ equality_check_kids("test_pi2", true);
+ equality_check_kids("test_pi3", false);
+ equality_check_kids("test_pi4", true);
+ equality_check_kids("test_pi5", true);
+
+ equality_check_kids("test_elt1", false);
+ equality_check_kids("test_elt2", false);
+ equality_check_kids("test_elt3", true);
+ equality_check_kids("test_elt4", false);
+ equality_check_kids("test_elt5", false);
+
+ equality_check_kids("test_comment1", true);
+ equality_check_kids("test_comment2", false);
+ equality_check_kids("test_comment3", false);
+ equality_check_kids("test_comment4", true);
+
+ equality_check_kids("test_text1", true);
+ equality_check_kids("test_text2", false);
+ equality_check_kids("test_text3", false);
+
+ equality_check_kids("test_cdata1", false);
+ equality_check_kids("test_cdata2", true);
+ equality_check_kids("test_cdata3", false);
+ equality_check_kids("test_cdata4", false);
+ equality_check_kids("test_cdata5", false);
+});
+
+add_task(function test_isEqualNode_namespaces() {
+ equality_check_kids("test_ns1", false);
+ equality_check_kids("test_ns2", false);
+
+ // XXX want more tests here!
+});
+
+// XXX This test is skipped:
+// should Node.isEqualNode(null) throw or return false?
+add_task(function test_isEqualNode_null() {
+ check_neq_nodes(doc, null);
+
+ var elts = doc.getElementsByTagName("*");
+ for (var i = 0; i < elts.length; i++) {
+ var elt = elts.item(i);
+ check_neq_nodes(elt, null);
+
+ var attrs = elt.attributes;
+ for (var j = 0; j < attrs.length; j++) {
+ var att = attrs.item(j);
+ check_neq_nodes(att, null);
+
+ for (var k = 0; k < att.childNodes.length; k++) {
+ check_neq_nodes(att.childNodes.item(k), null);
+ }
+ }
+ }
+}).skip();
+
+add_task(function test_isEqualNode_wholeDoc() {
+ doc = ParseFile("isequalnode_data.xml");
+ var doc2 = ParseFile("isequalnode_data.xml");
+ var tw1 = doc.createTreeWalker(doc, NodeFilter.SHOW_ALL, null);
+ var tw2 = doc2.createTreeWalker(doc2, NodeFilter.SHOW_ALL, null);
+ do {
+ check_eq_nodes(tw1.currentNode, tw2.currentNode);
+ tw1.nextNode();
+ } while (tw2.nextNode());
+});
+
+// TESTING FUNCTIONS
+
+/**
+ * Compares the first and third (zero-indexed) child nodes of the element
+ * (typically to allow whitespace) referenced by parentId for isEqualNode
+ * equality or inequality based on the value of areEqual.
+ *
+ * Note that this means that the contents of the element referenced by parentId
+ * are whitespace-sensitive, and a stray space introduced during an edit to the
+ * file could result in a correct but unexpected (in)equality failure.
+ */
+function equality_check_kids(parentId, areEqual) {
+ var parent = doc.getElementById(parentId);
+ var kid1 = parent.childNodes.item(1);
+ var kid2 = parent.childNodes.item(3);
+
+ if (areEqual) {
+ check_eq_nodes(kid1, kid2);
+ } else {
+ check_neq_nodes(kid1, kid2);
+ }
+}
+
+function check_eq_nodes(n1, n2) {
+ if (n1 && !n1.isEqualNode(n2)) {
+ do_throw(n1 + " should be equal to " + n2);
+ }
+ if (n2 && !n2.isEqualNode(n1)) {
+ do_throw(n2 + " should be equal to " + n1);
+ }
+ if (!n1 && !n2) {
+ do_throw("nodes both null!");
+ }
+}
+
+function check_neq_nodes(n1, n2) {
+ if (n1 && n1.isEqualNode(n2)) {
+ do_throw(n1 + " should not be equal to " + n2);
+ }
+ if (n2 && n2.isEqualNode(n1)) {
+ do_throw(n2 + " should not be equal to " + n1);
+ }
+ if (!n1 && !n2) {
+ do_throw("n1 and n2 both null!");
+ }
+}
diff --git a/dom/base/test/unit/test_js_dev_error_interceptor.js b/dom/base/test/unit/test_js_dev_error_interceptor.js
new file mode 100644
index 0000000000..8ccc0dcaf8
--- /dev/null
+++ b/dom/base/test/unit/test_js_dev_error_interceptor.js
@@ -0,0 +1,53 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+function errors() {
+ return [
+ // The following two errors MUST NOT be captured.
+ new Error("This is an error: " + Math.random()),
+ new RangeError("This is a RangeError: " + Math.random()),
+ new TypeError("This is a TypeError: " + Math.random()),
+ "This is a string: " + Math.random(),
+ null,
+ undefined,
+ Math.random(),
+ {},
+
+ // The following errors MUST be captured.
+ new SyntaxError("This is a SyntaxError: " + Math.random()),
+ new ReferenceError("This is a ReferenceError: " + Math.random()),
+ ];
+}
+
+function isDeveloperError(e) {
+ if (e == null || typeof e != "object") {
+ return false;
+ }
+
+ return e.constructor == SyntaxError || e.constructor == ReferenceError;
+}
+
+function run_test() {
+ ChromeUtils.clearRecentJSDevError();
+ Assert.equal(ChromeUtils.recentJSDevError, undefined);
+
+ for (let exn of errors()) {
+ ChromeUtils.clearRecentJSDevError();
+ try {
+ throw exn;
+ } catch (e) {
+ // Discard error.
+ }
+ if (isDeveloperError(exn)) {
+ Assert.equal(ChromeUtils.recentJSDevError.message, "" + exn);
+ } else {
+ Assert.equal(ChromeUtils.recentJSDevError, undefined);
+ }
+ ChromeUtils.clearRecentJSDevError();
+ Assert.equal(ChromeUtils.recentJSDevError, undefined);
+ }
+}
diff --git a/dom/base/test/unit/test_nodelist.js b/dom/base/test/unit/test_nodelist.js
new file mode 100644
index 0000000000..0ad24b9bd5
--- /dev/null
+++ b/dom/base/test/unit/test_nodelist.js
@@ -0,0 +1,345 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+function run_test() {
+ test_getElementsByTagName();
+ test_getElementsByTagNameNS();
+ test_getElementsByAttribute();
+ test_getElementsByAttributeNS();
+
+ // What else should we test?
+ // XXXbz we need more tests here to test liveness!
+}
+
+function test_getElementsByTagName() {
+ var doc = ParseFile("nodelist_data_1.xml");
+ var root = doc.documentElement;
+
+ // Check that getElementsByTagName returns an HTMLCollection.
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagName("*")),
+ "HTMLCollection"
+ );
+ Assert.ok(
+ ChromeUtils.getClassName(root.getElementsByTagName("*")),
+ "HTMLCollection"
+ );
+
+ // Check that getElementsByTagName excludes the element it's called on.
+ Assert.equal(
+ doc.getElementsByTagName("*").length,
+ root.getElementsByTagName("*").length + 1
+ );
+ Assert.equal(doc.getElementById("test2").getElementsByTagName("*").length, 8);
+ Assert.equal(
+ doc.getElementById("test2").getElementsByTagName("test").length,
+ 3
+ );
+
+ // Check that the first element of getElementsByTagName on the document is
+ // the right thing.
+ Assert.equal(doc.getElementsByTagName("*").item(0), root);
+
+ // Check that we get the right things in the right order
+ var numTests = doc.getElementsByTagName("test").length;
+ Assert.equal(numTests, 5);
+
+ for (var i = 1; i <= numTests; ++i) {
+ Assert.ok(Element.isInstance(doc.getElementById("test" + i)));
+ Assert.equal(
+ doc.getElementById("test" + i),
+ doc.getElementsByTagName("test").item(i - 1)
+ );
+ }
+
+ // Check that we handle tagnames containing ':' correctly
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagName("foo:test")),
+ "HTMLCollection"
+ );
+ Assert.equal(doc.getElementsByTagName("foo:test").length, 2);
+
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagName("foo2:test")),
+ "HTMLCollection"
+ );
+ Assert.equal(doc.getElementsByTagName("foo2:test").length, 3);
+
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagName("bar:test")),
+ "HTMLCollection"
+ );
+ Assert.equal(doc.getElementsByTagName("bar:test").length, 4);
+}
+
+function test_getElementsByTagNameNS() {
+ var doc = ParseFile("nodelist_data_1.xml");
+ var root = doc.documentElement;
+
+ // Check that getElementsByTagNameNS returns an HTMLCollection.
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagNameNS("*", "*")),
+ "HTMLCollection"
+ );
+ Assert.equal(
+ ChromeUtils.getClassName(root.getElementsByTagNameNS("*", "*")),
+ "HTMLCollection"
+ );
+
+ // Check that passing "" and null for the namespace URI gives the same result
+ var list1 = doc.getElementsByTagNameNS("", "test");
+ var list2 = doc.getElementsByTagNameNS(null, "test");
+ Assert.equal(list1.length, list2.length);
+ for (var i = 0; i < list1.length; ++i) {
+ Assert.equal(list1.item(i), list2.item(i));
+ }
+
+ // Check that getElementsByTagNameNS excludes the element it's called on.
+ Assert.equal(
+ doc.getElementsByTagNameNS("*", "*").length,
+ root.getElementsByTagNameNS("*", "*").length + 1
+ );
+ Assert.equal(
+ doc.getElementById("test2").getElementsByTagNameNS("*", "*").length,
+ 8
+ );
+ Assert.equal(
+ doc.getElementById("test2").getElementsByTagNameNS("", "test").length,
+ 1
+ );
+ Assert.equal(
+ doc.getElementById("test2").getElementsByTagNameNS("*", "test").length,
+ 7
+ );
+
+ // Check that the first element of getElementsByTagNameNS on the document is
+ // the right thing.
+ Assert.equal(doc.getElementsByTagNameNS("*", "*").item(0), root);
+ Assert.equal(doc.getElementsByTagNameNS(null, "*").item(0), root);
+
+ // Check that we get the right things in the right order
+
+ var numTests = doc.getElementsByTagNameNS("*", "test").length;
+ Assert.equal(numTests, 14);
+
+ for (i = 1; i <= numTests; ++i) {
+ Assert.ok(Element.isInstance(doc.getElementById("test" + i)));
+ Assert.equal(
+ doc.getElementById("test" + i),
+ doc.getElementsByTagNameNS("*", "test").item(i - 1)
+ );
+ }
+
+ // Check general proper functioning of having a non-wildcard namespace.
+ var test2 = doc.getElementById("test2");
+ Assert.equal(doc.getElementsByTagNameNS("", "test").length, 3);
+ Assert.equal(test2.getElementsByTagNameNS("", "test").length, 1);
+ Assert.equal(doc.getElementsByTagNameNS("foo", "test").length, 7);
+ Assert.equal(test2.getElementsByTagNameNS("foo", "test").length, 4);
+ Assert.equal(doc.getElementsByTagNameNS("foo2", "test").length, 0);
+ Assert.equal(test2.getElementsByTagNameNS("foo2", "test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("bar", "test").length, 4);
+ Assert.equal(test2.getElementsByTagNameNS("bar", "test").length, 2);
+
+ // Check that we handle tagnames containing ':' correctly
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagNameNS(null, "foo:test")),
+ "HTMLCollection"
+ );
+ Assert.equal(doc.getElementsByTagNameNS(null, "foo:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("foo", "foo:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("bar", "foo:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("*", "foo:test").length, 0);
+
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagNameNS(null, "foo2:test")),
+ "HTMLCollection"
+ );
+ Assert.equal(doc.getElementsByTagNameNS(null, "foo2:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("foo2", "foo2:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("bar", "foo2:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("*", "foo2:test").length, 0);
+
+ Assert.equal(
+ ChromeUtils.getClassName(doc.getElementsByTagNameNS(null, "bar:test")),
+ "HTMLCollection"
+ );
+ Assert.equal(doc.getElementsByTagNameNS(null, "bar:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("bar", "bar:test").length, 0);
+ Assert.equal(doc.getElementsByTagNameNS("*", "bar:test").length, 0);
+
+ // Check that previously-unknown namespaces are handled right. Note that we
+ // can just hardcode the strings, since we're running only once in XPCshell.
+ // If someone wants to run these in a browser, some use of Math.random() may
+ // be in order.
+ list1 = doc.getElementsByTagNameNS("random-bogus-namespace", "foo");
+ list2 = doc.documentElement.getElementsByTagNameNS(
+ "random-bogus-namespace2",
+ "foo"
+ );
+ Assert.notEqual(list1, list2);
+ Assert.equal(list1.length, 0);
+ Assert.equal(list2.length, 0);
+ var newNode = doc.createElementNS("random-bogus-namespace", "foo");
+ doc.documentElement.appendChild(newNode);
+ newNode = doc.createElementNS("random-bogus-namespace2", "foo");
+ doc.documentElement.appendChild(newNode);
+ Assert.equal(list1.length, 1);
+ Assert.equal(list2.length, 1);
+}
+
+function test_getElementsByAttribute() {
+ var doc = ParseFile("nodelist_data_2.xhtml");
+ var root = doc.documentElement;
+
+ Assert.equal(ChromeUtils.getClassName(root), "XULElement");
+
+ Assert.equal(
+ ChromeUtils.getClassName(root.getElementsByAttribute("foo", "foo")),
+ "HTMLCollection"
+ );
+
+ var master1 = doc.getElementById("master1");
+ var master2 = doc.getElementById("master2");
+ var master3 = doc.getElementById("master3");
+ var external = doc.getElementById("external");
+
+ Assert.equal(ChromeUtils.getClassName(master1), "XULElement");
+ Assert.equal(ChromeUtils.getClassName(master2), "XULElement");
+ Assert.equal(ChromeUtils.getClassName(master3), "XULElement");
+ Assert.equal(ChromeUtils.getClassName(external), "XULElement");
+
+ // Basic tests
+ Assert.equal(root.getElementsByAttribute("foo", "foo").length, 14);
+ Assert.equal(master1.getElementsByAttribute("foo", "foo").length, 4);
+
+ Assert.equal(root.getElementsByAttribute("foo", "bar").length, 7);
+ Assert.equal(master1.getElementsByAttribute("foo", "bar").length, 2);
+
+ Assert.equal(root.getElementsByAttribute("bar", "bar").length, 7);
+ Assert.equal(master1.getElementsByAttribute("bar", "bar").length, 2);
+
+ Assert.equal(root.getElementsByAttribute("foo", "*").length, 21);
+ Assert.equal(master1.getElementsByAttribute("foo", "*").length, 6);
+
+ // Test the various combinations of attributes with colons in the name
+ Assert.equal(root.getElementsByAttribute("foo:foo", "foo").length, 16);
+ Assert.equal(master1.getElementsByAttribute("foo:foo", "foo").length, 5);
+ Assert.equal(master2.getElementsByAttribute("foo:foo", "foo").length, 4);
+ Assert.equal(master3.getElementsByAttribute("foo:foo", "foo").length, 4);
+ Assert.equal(external.getElementsByAttribute("foo:foo", "foo").length, 2);
+
+ Assert.equal(root.getElementsByAttribute("foo:foo", "bar").length, 9);
+ Assert.equal(master1.getElementsByAttribute("foo:foo", "bar").length, 2);
+ Assert.equal(master2.getElementsByAttribute("foo:foo", "bar").length, 3);
+ Assert.equal(master3.getElementsByAttribute("foo:foo", "bar").length, 2);
+ Assert.equal(external.getElementsByAttribute("foo:foo", "bar").length, 1);
+
+ Assert.equal(root.getElementsByAttribute("foo:bar", "foo").length, 7);
+ Assert.equal(master1.getElementsByAttribute("foo:bar", "foo").length, 2);
+ Assert.equal(master2.getElementsByAttribute("foo:bar", "foo").length, 2);
+ Assert.equal(master3.getElementsByAttribute("foo:bar", "foo").length, 2);
+ Assert.equal(external.getElementsByAttribute("foo:bar", "foo").length, 1);
+
+ Assert.equal(root.getElementsByAttribute("foo:bar", "bar").length, 14);
+ Assert.equal(master1.getElementsByAttribute("foo:bar", "bar").length, 4);
+ Assert.equal(master2.getElementsByAttribute("foo:bar", "bar").length, 4);
+ Assert.equal(master3.getElementsByAttribute("foo:bar", "bar").length, 4);
+ Assert.equal(external.getElementsByAttribute("foo:bar", "bar").length, 2);
+
+ Assert.equal(root.getElementsByAttribute("foo2:foo", "foo").length, 8);
+ Assert.equal(master1.getElementsByAttribute("foo2:foo", "foo").length, 2);
+ Assert.equal(master2.getElementsByAttribute("foo2:foo", "foo").length, 2);
+ Assert.equal(master3.getElementsByAttribute("foo2:foo", "foo").length, 3);
+ Assert.equal(external.getElementsByAttribute("foo2:foo", "foo").length, 1);
+
+ Assert.equal(root.getElementsByAttribute("foo:foo", "*").length, 25);
+ Assert.equal(master1.getElementsByAttribute("foo:foo", "*").length, 7);
+ Assert.equal(master2.getElementsByAttribute("foo:foo", "*").length, 7);
+ Assert.equal(master3.getElementsByAttribute("foo:foo", "*").length, 6);
+ Assert.equal(external.getElementsByAttribute("foo:foo", "*").length, 3);
+
+ Assert.equal(root.getElementsByAttribute("foo2:foo", "bar").length, 0);
+ Assert.equal(root.getElementsByAttribute("foo:foo", "baz").length, 0);
+}
+
+function test_getElementsByAttributeNS() {
+ var doc = ParseFile("nodelist_data_2.xhtml");
+ var root = doc.documentElement;
+
+ Assert.equal(ChromeUtils.getClassName(root), "XULElement");
+
+ // Check that getElementsByAttributeNS returns an HTMLCollection.
+ Assert.equal(
+ ChromeUtils.getClassName(root.getElementsByAttributeNS("*", "*", "*")),
+ "HTMLCollection"
+ );
+
+ var master1 = doc.getElementById("master1");
+ var master2 = doc.getElementById("master2");
+ var master3 = doc.getElementById("master3");
+ var external = doc.getElementById("external");
+
+ Assert.equal(ChromeUtils.getClassName(master1), "XULElement");
+ Assert.equal(ChromeUtils.getClassName(master2), "XULElement");
+ Assert.equal(ChromeUtils.getClassName(master3), "XULElement");
+ Assert.equal(ChromeUtils.getClassName(external), "XULElement");
+
+ // Test wildcard namespace
+ Assert.equal(root.getElementsByAttributeNS("*", "foo", "foo").length, 38);
+ Assert.equal(master1.getElementsByAttributeNS("*", "foo", "foo").length, 11);
+ Assert.equal(master2.getElementsByAttributeNS("*", "foo", "foo").length, 10);
+ Assert.equal(master3.getElementsByAttributeNS("*", "foo", "foo").length, 11);
+
+ Assert.equal(root.getElementsByAttributeNS("*", "foo", "bar").length, 16);
+ Assert.equal(master1.getElementsByAttributeNS("*", "foo", "bar").length, 4);
+ Assert.equal(master2.getElementsByAttributeNS("*", "foo", "bar").length, 5);
+ Assert.equal(master3.getElementsByAttributeNS("*", "foo", "bar").length, 4);
+
+ Assert.equal(root.getElementsByAttributeNS("*", "bar", "bar").length, 21);
+ Assert.equal(master1.getElementsByAttributeNS("*", "bar", "bar").length, 6);
+ Assert.equal(master2.getElementsByAttributeNS("*", "bar", "bar").length, 6);
+ Assert.equal(master3.getElementsByAttributeNS("*", "bar", "bar").length, 6);
+
+ Assert.equal(root.getElementsByAttributeNS("*", "foo", "*").length, 54);
+ Assert.equal(master1.getElementsByAttributeNS("*", "foo", "*").length, 15);
+ Assert.equal(master2.getElementsByAttributeNS("*", "foo", "*").length, 15);
+ Assert.equal(master3.getElementsByAttributeNS("*", "foo", "*").length, 15);
+
+ // Test null namespace. This should be the same as getElementsByAttribute.
+ Assert.equal(
+ root.getElementsByAttributeNS("", "foo", "foo").length,
+ root.getElementsByAttribute("foo", "foo").length
+ );
+ Assert.equal(
+ master1.getElementsByAttributeNS("", "foo", "foo").length,
+ master1.getElementsByAttribute("foo", "foo").length
+ );
+ Assert.equal(
+ master2.getElementsByAttributeNS("", "foo", "foo").length,
+ master2.getElementsByAttribute("foo", "foo").length
+ );
+ Assert.equal(
+ master3.getElementsByAttributeNS("", "foo", "foo").length,
+ master3.getElementsByAttribute("foo", "foo").length
+ );
+
+ // Test namespace "foo"
+ Assert.equal(root.getElementsByAttributeNS("foo", "foo", "foo").length, 24);
+ Assert.equal(master1.getElementsByAttributeNS("foo", "foo", "foo").length, 7);
+ Assert.equal(master2.getElementsByAttributeNS("foo", "foo", "foo").length, 6);
+ Assert.equal(master3.getElementsByAttributeNS("foo", "foo", "foo").length, 7);
+
+ Assert.equal(root.getElementsByAttributeNS("foo", "foo", "bar").length, 9);
+ Assert.equal(master1.getElementsByAttributeNS("foo", "foo", "bar").length, 2);
+ Assert.equal(master2.getElementsByAttributeNS("foo", "foo", "bar").length, 3);
+ Assert.equal(master3.getElementsByAttributeNS("foo", "foo", "bar").length, 2);
+
+ Assert.equal(root.getElementsByAttributeNS("foo", "bar", "foo").length, 7);
+ Assert.equal(master1.getElementsByAttributeNS("foo", "bar", "foo").length, 2);
+ Assert.equal(master2.getElementsByAttributeNS("foo", "bar", "foo").length, 2);
+ Assert.equal(master3.getElementsByAttributeNS("foo", "bar", "foo").length, 2);
+
+ Assert.equal(root.getElementsByAttributeNS("foo", "bar", "bar").length, 14);
+ Assert.equal(master1.getElementsByAttributeNS("foo", "bar", "bar").length, 4);
+ Assert.equal(master2.getElementsByAttributeNS("foo", "bar", "bar").length, 4);
+ Assert.equal(master3.getElementsByAttributeNS("foo", "bar", "bar").length, 4);
+}
diff --git a/dom/base/test/unit/test_normalize.js b/dom/base/test/unit/test_normalize.js
new file mode 100644
index 0000000000..b7d89f14f8
--- /dev/null
+++ b/dom/base/test/unit/test_normalize.js
@@ -0,0 +1,100 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function run_test() {
+ /*
+ * NOTE: [i] is not allowed in this test, since it's done via classinfo and
+ * we don't have that in xpcshell; the workaround is item(i). Suck.
+ */
+ init();
+
+ test_element();
+
+ // more tests would be nice here (such as for documents), but the primary
+ // uses of Node.normalize() are in test_element; stuff beyond this is either
+ // unimplemented or is unlikely to be used all that much within a browser
+ // DOM implementation
+}
+
+// TEST CODE
+
+var doc; // cache for use in all tests
+
+function init() {
+ doc = ParseFile("empty_document.xml");
+}
+
+function test_element() {
+ var x = doc.createElement("funk");
+
+ // one empty Text node
+ x.appendChild(doc.createTextNode(""));
+ Assert.equal(x.childNodes.length, 1);
+
+ x.normalize();
+ Assert.equal(x.childNodes.length, 0);
+
+ // multiple empty Text nodes
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(doc.createTextNode(""));
+ Assert.equal(x.childNodes.length, 2);
+
+ x.normalize();
+ Assert.equal(x.childNodes.length, 0);
+
+ // empty Text node followed by other Text node
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ Assert.equal(x.childNodes.length, 2);
+
+ x.normalize();
+ Assert.equal(x.childNodes.length, 1);
+ Assert.equal(x.childNodes.item(0).nodeValue, "Guaraldi");
+
+ // Text node followed by empty Text node
+ clearKids(x);
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ x.appendChild(doc.createTextNode(""));
+ Assert.equal(x.childNodes.length, 2);
+
+ x.normalize();
+ Assert.equal(x.childNodes.item(0).nodeValue, "Guaraldi");
+
+ // Text node followed by empty Text node followed by other Node
+ clearKids(x);
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(doc.createElement("jazzy"));
+ Assert.equal(x.childNodes.length, 3);
+
+ x.normalize();
+ Assert.equal(x.childNodes.length, 2);
+ Assert.equal(x.childNodes.item(0).nodeValue, "Guaraldi");
+ Assert.equal(x.childNodes.item(1).nodeName, "jazzy");
+
+ // Nodes are recursively normalized
+ clearKids(x);
+ var kid = doc.createElement("eit");
+ kid.appendChild(doc.createTextNode(""));
+
+ x.appendChild(doc.createTextNode("Guaraldi"));
+ x.appendChild(doc.createTextNode(""));
+ x.appendChild(kid);
+ Assert.equal(x.childNodes.length, 3);
+ Assert.equal(x.childNodes.item(2).childNodes.length, 1);
+
+ x.normalize();
+ Assert.equal(x.childNodes.length, 2);
+ Assert.equal(x.childNodes.item(0).nodeValue, "Guaraldi");
+ Assert.equal(x.childNodes.item(1).childNodes.length, 0);
+}
+
+// UTILITY FUNCTIONS
+
+function clearKids(node) {
+ while (node.hasChildNodes()) {
+ node.removeChild(node.childNodes.item(0));
+ }
+}
diff --git a/dom/base/test/unit/test_range.js b/dom/base/test/unit/test_range.js
new file mode 100644
index 0000000000..8b9f5c0b8b
--- /dev/null
+++ b/dom/base/test/unit/test_range.js
@@ -0,0 +1,465 @@
+/* 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/. */
+
+const UNORDERED_TYPE = 8; // XPathResult.ANY_UNORDERED_NODE_TYPE
+
+/**
+ * Determine if the data node has only ignorable white-space.
+ *
+ * @return NodeFilter.FILTER_SKIP if it does.
+ * @return NodeFilter.FILTER_ACCEPT otherwise.
+ */
+function isWhitespace(aNode) {
+ return /\S/.test(aNode.nodeValue)
+ ? NodeFilter.FILTER_SKIP
+ : NodeFilter.FILTER_ACCEPT;
+}
+
+/**
+ * Create a DocumentFragment with cloned children equaling a node's children.
+ *
+ * @param aNode The node to copy from.
+ *
+ * @return DocumentFragment node.
+ */
+function getFragment(aNode) {
+ var frag = aNode.ownerDocument.createDocumentFragment();
+ for (var i = 0; i < aNode.childNodes.length; i++) {
+ frag.appendChild(aNode.childNodes.item(i).cloneNode(true));
+ }
+ return frag;
+}
+
+// Goodies from head_content.js
+const parser = getParser();
+
+/**
+ * Translate an XPath to a DOM node. This method uses a document
+ * fragment as context node.
+ *
+ * @param aContextNode The context node to apply the XPath to.
+ * @param aPath The XPath to use.
+ *
+ * @return Node The target node retrieved from the XPath.
+ */
+function evalXPathInDocumentFragment(aContextNode, aPath) {
+ Assert.equal(ChromeUtils.getClassName(aContextNode), "DocumentFragment");
+ Assert.ok(aContextNode.childNodes.length);
+ if (aPath == ".") {
+ return aContextNode;
+ }
+
+ // Separate the fragment's xpath lookup from the rest.
+ var firstSlash = aPath.indexOf("/");
+ if (firstSlash == -1) {
+ firstSlash = aPath.length;
+ }
+ var prefix = aPath.substr(0, firstSlash);
+ var realPath = aPath.substr(firstSlash + 1);
+ if (!realPath) {
+ realPath = ".";
+ }
+
+ // Set up a special node filter to look among the fragment's child nodes.
+ var childIndex = 1;
+ var bracketIndex = prefix.indexOf("[");
+ if (bracketIndex != -1) {
+ childIndex = Number(
+ prefix.substring(bracketIndex + 1, prefix.indexOf("]"))
+ );
+ Assert.ok(childIndex > 0);
+ prefix = prefix.substr(0, bracketIndex);
+ }
+
+ var targetType = NodeFilter.SHOW_ELEMENT;
+ var targetNodeName = prefix;
+ if (prefix.indexOf("processing-instruction(") == 0) {
+ targetType = NodeFilter.SHOW_PROCESSING_INSTRUCTION;
+ targetNodeName = prefix.substring(
+ prefix.indexOf("(") + 2,
+ prefix.indexOf(")") - 1
+ );
+ }
+ switch (prefix) {
+ case "text()":
+ targetType = NodeFilter.SHOW_TEXT | NodeFilter.SHOW_CDATA_SECTION;
+ targetNodeName = null;
+ break;
+ case "comment()":
+ targetType = NodeFilter.SHOW_COMMENT;
+ targetNodeName = null;
+ break;
+ case "node()":
+ targetType = NodeFilter.SHOW_ALL;
+ targetNodeName = null;
+ }
+
+ var filter = {
+ count: 0,
+
+ // NodeFilter
+ acceptNode: function acceptNode(aNode) {
+ if (aNode.parentNode != aContextNode) {
+ // Don't bother looking at kids either.
+ return NodeFilter.FILTER_REJECT;
+ }
+
+ if (targetNodeName && targetNodeName != aNode.nodeName) {
+ return NodeFilter.FILTER_SKIP;
+ }
+
+ this.count++;
+ if (this.count != childIndex) {
+ return NodeFilter.FILTER_SKIP;
+ }
+
+ return NodeFilter.FILTER_ACCEPT;
+ },
+ };
+
+ // Look for the node matching the step from the document fragment.
+ var walker = aContextNode.ownerDocument.createTreeWalker(
+ aContextNode,
+ targetType,
+ filter
+ );
+ var targetNode = walker.nextNode();
+ Assert.notEqual(targetNode, null);
+
+ // Apply our remaining xpath to the found node.
+ var expr = aContextNode.ownerDocument.createExpression(realPath, null);
+ var result = expr.evaluate(targetNode, UNORDERED_TYPE, null);
+ return result.singleNodeValue;
+}
+
+/**
+ * Get a DOM range corresponding to the test's source node.
+ *
+ * @param aSourceNode <source/> element with range information.
+ * @param aFragment DocumentFragment generated with getFragment().
+ *
+ * @return Range object.
+ */
+function getRange(aSourceNode, aFragment) {
+ Assert.ok(Element.isInstance(aSourceNode));
+ Assert.equal(ChromeUtils.getClassName(aFragment), "DocumentFragment");
+ var doc = aSourceNode.ownerDocument;
+
+ var containerPath = aSourceNode.getAttribute("startContainer");
+ var startContainer = evalXPathInDocumentFragment(aFragment, containerPath);
+ var startOffset = Number(aSourceNode.getAttribute("startOffset"));
+
+ containerPath = aSourceNode.getAttribute("endContainer");
+ var endContainer = evalXPathInDocumentFragment(aFragment, containerPath);
+ var endOffset = Number(aSourceNode.getAttribute("endOffset"));
+
+ var range = doc.createRange();
+ range.setStart(startContainer, startOffset);
+ range.setEnd(endContainer, endOffset);
+ return range;
+}
+
+/**
+ * Get the document for a given path, and clean it up for our tests.
+ *
+ * @param aPath The path to the local document.
+ */
+function getParsedDocument(aPath) {
+ return do_parse_document(aPath, "application/xml").then(
+ processParsedDocument
+ );
+}
+
+function processParsedDocument(doc) {
+ Assert.ok(doc.documentElement.localName != "parsererror");
+ Assert.equal(ChromeUtils.getClassName(doc), "XMLDocument");
+
+ // Clean out whitespace.
+ var walker = doc.createTreeWalker(
+ doc,
+ NodeFilter.SHOW_TEXT | NodeFilter.SHOW_CDATA_SECTION,
+ isWhitespace
+ );
+ while (walker.nextNode()) {
+ var parent = walker.currentNode.parentNode;
+ parent.removeChild(walker.currentNode);
+ walker.currentNode = parent;
+ }
+
+ // Clean out mandatory splits between nodes.
+ var splits = doc.getElementsByTagName("split");
+ var i;
+ for (i = splits.length - 1; i >= 0; i--) {
+ let node = splits.item(i);
+ node.remove();
+ }
+ splits = null;
+
+ // Replace empty CDATA sections.
+ var emptyData = doc.getElementsByTagName("empty-cdata");
+ for (i = emptyData.length - 1; i >= 0; i--) {
+ let node = emptyData.item(i);
+ var cdata = doc.createCDATASection("");
+ node.parentNode.replaceChild(cdata, node);
+ }
+
+ return doc;
+}
+
+/**
+ * Run the extraction tests.
+ */
+function run_extract_test() {
+ var filePath = "test_delete_range.xml";
+ getParsedDocument(filePath).then(do_extract_test);
+}
+
+function do_extract_test(doc) {
+ var tests = doc.getElementsByTagName("test");
+
+ // Run our deletion, extraction tests.
+ for (var i = 0; i < tests.length; i++) {
+ dump("Configuring for test " + i + "\n");
+ var currentTest = tests.item(i);
+
+ // Validate the test is properly formatted for what this harness expects.
+ var baseSource = currentTest.firstChild;
+ Assert.equal(baseSource.nodeName, "source");
+ var baseResult = baseSource.nextSibling;
+ Assert.equal(baseResult.nodeName, "result");
+ var baseExtract = baseResult.nextSibling;
+ Assert.equal(baseExtract.nodeName, "extract");
+ Assert.equal(baseExtract.nextSibling, null);
+
+ /* We do all our tests on DOM document fragments, derived from the test
+ element's children. This lets us rip the various fragments to shreds,
+ while preserving the original elements so we can make more copies of
+ them.
+
+ After the range's extraction or deletion is done, we use
+ Node.isEqualNode() between the altered source fragment and the
+ result fragment. We also run isEqualNode() between the extracted
+ fragment and the fragment from the baseExtract node. If they are not
+ equal, we have failed a test.
+
+ We also have to ensure the original nodes on the end points of the
+ range are still in the source fragment. This is bug 332148. The nodes
+ may not be replaced with equal but separate nodes. The range extraction
+ may alter these nodes - in the case of text containers, they will - but
+ the nodes must stay there, to preserve references such as user data,
+ event listeners, etc.
+
+ First, an extraction test.
+ */
+
+ var resultFrag = getFragment(baseResult);
+ var extractFrag = getFragment(baseExtract);
+
+ dump("Extract contents test " + i + "\n\n");
+ var baseFrag = getFragment(baseSource);
+ var baseRange = getRange(baseSource, baseFrag);
+ var startContainer = baseRange.startContainer;
+ var endContainer = baseRange.endContainer;
+
+ var cutFragment = baseRange.extractContents();
+ dump("cutFragment: " + cutFragment + "\n");
+ if (cutFragment) {
+ Assert.ok(extractFrag.isEqualNode(cutFragment));
+ } else {
+ Assert.equal(extractFrag.firstChild, null);
+ }
+ Assert.ok(baseFrag.isEqualNode(resultFrag));
+
+ dump("Ensure the original nodes weren't extracted - test " + i + "\n\n");
+ var walker = doc.createTreeWalker(baseFrag, NodeFilter.SHOW_ALL, null);
+ var foundStart = false;
+ var foundEnd = false;
+ do {
+ if (walker.currentNode == startContainer) {
+ foundStart = true;
+ }
+
+ if (walker.currentNode == endContainer) {
+ // An end container node should not come before the start container node.
+ Assert.ok(foundStart);
+ foundEnd = true;
+ break;
+ }
+ } while (walker.nextNode());
+ Assert.ok(foundEnd);
+
+ /* Now, we reset our test for the deleteContents case. This one differs
+ from the extractContents case only in that there is no extracted document
+ fragment to compare against. So we merely compare the starting fragment,
+ minus the extracted content, against the result fragment.
+ */
+ dump("Delete contents test " + i + "\n\n");
+ baseFrag = getFragment(baseSource);
+ baseRange = getRange(baseSource, baseFrag);
+ startContainer = baseRange.startContainer;
+ endContainer = baseRange.endContainer;
+ baseRange.deleteContents();
+ Assert.ok(baseFrag.isEqualNode(resultFrag));
+
+ dump("Ensure the original nodes weren't deleted - test " + i + "\n\n");
+ walker = doc.createTreeWalker(baseFrag, NodeFilter.SHOW_ALL, null);
+ foundStart = false;
+ foundEnd = false;
+ do {
+ if (walker.currentNode == startContainer) {
+ foundStart = true;
+ }
+
+ if (walker.currentNode == endContainer) {
+ // An end container node should not come before the start container node.
+ Assert.ok(foundStart);
+ foundEnd = true;
+ break;
+ }
+ } while (walker.nextNode());
+ Assert.ok(foundEnd);
+
+ // Clean up after ourselves.
+ walker = null;
+ }
+}
+
+/**
+ * Miscellaneous tests not covered above.
+ */
+function run_miscellaneous_tests() {
+ var filePath = "test_delete_range.xml";
+ getParsedDocument(filePath).then(do_miscellaneous_tests);
+}
+
+function isText(node) {
+ return (
+ node.nodeType == node.TEXT_NODE || node.nodeType == node.CDATA_SECTION_NODE
+ );
+}
+
+function do_miscellaneous_tests(doc) {
+ var tests = doc.getElementsByTagName("test");
+
+ // Let's try some invalid inputs to our DOM range and see what happens.
+ var currentTest = tests.item(0);
+ var baseSource = currentTest.firstChild;
+
+ var baseFrag = getFragment(baseSource);
+
+ var baseRange = getRange(baseSource, baseFrag);
+ var startContainer = baseRange.startContainer;
+ var endContainer = baseRange.endContainer;
+ var startOffset = baseRange.startOffset;
+ var endOffset = baseRange.endOffset;
+
+ // Text range manipulation.
+ if (
+ endOffset > startOffset &&
+ startContainer == endContainer &&
+ isText(startContainer)
+ ) {
+ // Invalid start node
+ try {
+ baseRange.setStart(null, 0);
+ do_throw("Should have thrown NOT_OBJECT_ERR!");
+ } catch (e) {
+ Assert.equal(e.constructor.name, "TypeError");
+ }
+
+ // Invalid start node
+ try {
+ baseRange.setStart({}, 0);
+ do_throw("Should have thrown SecurityError!");
+ } catch (e) {
+ Assert.equal(e.constructor.name, "TypeError");
+ }
+
+ // Invalid index
+ try {
+ baseRange.setStart(startContainer, -1);
+ do_throw("Should have thrown IndexSizeError!");
+ } catch (e) {
+ Assert.equal(e.name, "IndexSizeError");
+ }
+
+ // Invalid index
+ var newOffset = isText(startContainer)
+ ? startContainer.nodeValue.length + 1
+ : startContainer.childNodes.length + 1;
+ try {
+ baseRange.setStart(startContainer, newOffset);
+ do_throw("Should have thrown IndexSizeError!");
+ } catch (e) {
+ Assert.equal(e.name, "IndexSizeError");
+ }
+
+ newOffset--;
+ // Valid index
+ baseRange.setStart(startContainer, newOffset);
+ Assert.equal(baseRange.startContainer, baseRange.endContainer);
+ Assert.equal(baseRange.startOffset, newOffset);
+ Assert.ok(baseRange.collapsed);
+
+ // Valid index
+ baseRange.setEnd(startContainer, 0);
+ Assert.equal(baseRange.startContainer, baseRange.endContainer);
+ Assert.equal(baseRange.startOffset, 0);
+ Assert.ok(baseRange.collapsed);
+ } else {
+ do_throw(
+ "The first test should be a text-only range test. Test is invalid."
+ );
+ }
+
+ /* See what happens when a range has a startContainer in one fragment, and an
+ endContainer in another. According to the DOM spec, section 2.4, the range
+ should collapse to the new container and offset. */
+ baseRange = getRange(baseSource, baseFrag);
+ startContainer = baseRange.startContainer;
+ startOffset = baseRange.startOffset;
+ endContainer = baseRange.endContainer;
+ endOffset = baseRange.endOffset;
+
+ dump("External fragment test\n\n");
+
+ var externalTest = tests.item(1);
+ var externalSource = externalTest.firstChild;
+ var externalFrag = getFragment(externalSource);
+ var externalRange = getRange(externalSource, externalFrag);
+
+ baseRange.setEnd(externalRange.endContainer, 0);
+ Assert.equal(baseRange.startContainer, externalRange.endContainer);
+ Assert.equal(baseRange.startOffset, 0);
+ Assert.ok(baseRange.collapsed);
+
+ /*
+ // XXX ajvincent if rv == WRONG_DOCUMENT_ERR, return false?
+ do_check_false(baseRange.isPointInRange(startContainer, startOffset));
+ do_check_false(baseRange.isPointInRange(startContainer, startOffset + 1));
+ do_check_false(baseRange.isPointInRange(endContainer, endOffset));
+ */
+
+ // Requested by smaug: A range involving a comment as a document child.
+ doc = parser.parseFromString("<!-- foo --><foo/>", "application/xml");
+ Assert.equal(ChromeUtils.getClassName(doc), "XMLDocument");
+ Assert.equal(doc.childNodes.length, 2);
+ baseRange = doc.createRange();
+ baseRange.setStart(doc.firstChild, 1);
+ baseRange.setEnd(doc.firstChild, 2);
+ var frag = baseRange.extractContents();
+ Assert.equal(frag.childNodes.length, 1);
+ Assert.ok(ChromeUtils.getClassName(frag.firstChild) == "Comment");
+ Assert.equal(frag.firstChild.nodeType, frag.COMMENT_NODE);
+ Assert.equal(frag.firstChild.nodeValue, "f");
+
+ /* smaug also requested attribute tests. Sadly, those are not yet supported
+ in ranges - see https://bugzilla.mozilla.org/show_bug.cgi?id=302775.
+ */
+}
+
+function run_test() {
+ run_extract_test();
+ run_miscellaneous_tests();
+}
diff --git a/dom/base/test/unit/test_serializers_entities.js b/dom/base/test/unit/test_serializers_entities.js
new file mode 100644
index 0000000000..55778ce3d6
--- /dev/null
+++ b/dom/base/test/unit/test_serializers_entities.js
@@ -0,0 +1,99 @@
+const encoders = {
+ xml: doc => {
+ let enc = Cu.createDocumentEncoder("text/xml");
+ enc.init(doc, "text/xml", Ci.nsIDocumentEncoder.OutputLFLineBreak);
+ return enc;
+ },
+ html: doc => {
+ let enc = Cu.createDocumentEncoder("text/html");
+ enc.init(doc, "text/html", Ci.nsIDocumentEncoder.OutputLFLineBreak);
+ return enc;
+ },
+ htmlBasic: doc => {
+ let enc = Cu.createDocumentEncoder("text/html");
+ enc.init(
+ doc,
+ "text/html",
+ Ci.nsIDocumentEncoder.OutputEncodeBasicEntities |
+ Ci.nsIDocumentEncoder.OutputLFLineBreak
+ );
+ return enc;
+ },
+ xhtml: doc => {
+ let enc = Cu.createDocumentEncoder("application/xhtml+xml");
+ enc.init(
+ doc,
+ "application/xhtml+xml",
+ Ci.nsIDocumentEncoder.OutputLFLineBreak
+ );
+ return enc;
+ },
+};
+
+// Which characters should we encode as entities? It depends on the serializer.
+const encodeAll = { html: true, htmlBasic: true, xhtml: true, xml: true };
+const encodeHTMLBasic = {
+ html: false,
+ htmlBasic: true,
+ xhtml: false,
+ xml: false,
+};
+const encodeXML = { html: false, htmlBasic: false, xhtml: true, xml: true };
+const encodeNone = { html: false, htmlBasic: false, xhtml: false, xml: false };
+const encodingInfoMap = new Map([
+ // Basic sanity chars '<', '>', '"', '&' get encoded in all cases.
+ ["<", encodeAll],
+ [">", encodeAll],
+ ["&", encodeAll],
+ // nbsp is only encoded with the HTML encoder when encoding basic entities.
+ ["\xA0", encodeHTMLBasic],
+]);
+
+const encodingMap = new Map([
+ ["<", "&lt;"],
+ [">", "&gt;"],
+ ["&", "&amp;"],
+ // nbsp is only encoded with the HTML encoder when encoding basic entities.
+ ["\xA0", "&nbsp;"],
+]);
+
+function encodingInfoForChar(c) {
+ var info = encodingInfoMap.get(c);
+ if (info) {
+ return info;
+ }
+ return encodeNone;
+}
+
+function encodingForChar(c, type) {
+ var info = encodingInfoForChar(c);
+ if (!info[type]) {
+ return c;
+ }
+ return encodingMap.get(c);
+}
+
+const doc = new DOMParser().parseFromString("<root></root>", "text/xml");
+const root = doc.documentElement;
+for (let i = 0; i < 255; ++i) {
+ let el = doc.createElement("span");
+ el.textContent = String.fromCharCode(i);
+ root.appendChild(el);
+}
+for (let type of ["xml", "xhtml", "htmlBasic", "html"]) {
+ let str = encoders[type](doc).encodeToString();
+ const prefix = "<root><span>";
+ const suffix = "</span></root>";
+ Assert.ok(str.startsWith(prefix), `${type} serialization starts correctly`);
+ Assert.ok(str.endsWith(suffix), `${type} serialization ends correctly`);
+ str = str.substring(prefix.length, str.length - suffix.length);
+ let encodings = str.split("</span><span>");
+ for (let i = 0; i < 255; ++i) {
+ let c = String.fromCharCode(i);
+ Assert.equal(
+ encodingForChar(c, type),
+ encodings[i],
+ `${type} encoding of char ${i} is correct`
+ );
+ }
+}
diff --git a/dom/base/test/unit/test_serializers_entities_in_attr.js b/dom/base/test/unit/test_serializers_entities_in_attr.js
new file mode 100644
index 0000000000..2497a480a7
--- /dev/null
+++ b/dom/base/test/unit/test_serializers_entities_in_attr.js
@@ -0,0 +1,108 @@
+const encoders = {
+ xml: doc => {
+ let enc = Cu.createDocumentEncoder("text/xml");
+ enc.init(doc, "text/xml", Ci.nsIDocumentEncoder.OutputLFLineBreak);
+ return enc;
+ },
+ html: doc => {
+ let enc = Cu.createDocumentEncoder("text/html");
+ enc.init(doc, "text/html", Ci.nsIDocumentEncoder.OutputLFLineBreak);
+ return enc;
+ },
+ htmlBasic: doc => {
+ let enc = Cu.createDocumentEncoder("text/html");
+ enc.init(
+ doc,
+ "text/html",
+ Ci.nsIDocumentEncoder.OutputEncodeBasicEntities |
+ Ci.nsIDocumentEncoder.OutputLFLineBreak
+ );
+ return enc;
+ },
+ xhtml: doc => {
+ let enc = Cu.createDocumentEncoder("application/xhtml+xml");
+ enc.init(
+ doc,
+ "application/xhtml+xml",
+ Ci.nsIDocumentEncoder.OutputLFLineBreak
+ );
+ return enc;
+ },
+};
+
+// Which characters should we encode as entities? It depends on the serializer.
+const encodeAll = { html: true, htmlBasic: true, xhtml: true, xml: true };
+const encodeHTMLBasic = {
+ html: false,
+ htmlBasic: true,
+ xhtml: false,
+ xml: false,
+};
+const encodeXML = { html: false, htmlBasic: false, xhtml: true, xml: true };
+const encodeNone = { html: false, htmlBasic: false, xhtml: false, xml: false };
+const encodingInfoMap = new Map([
+ // Basic sanity chars '<', '>', '"', '&' get encoded in all cases.
+ ["<", encodeAll],
+ [">", encodeAll],
+ ['"', encodeAll],
+ ["&", encodeAll],
+ // nbsp is only encoded with the HTML encoder when encoding basic entities.
+ ["\xA0", encodeHTMLBasic],
+ // Whitespace bits are only encoded in XML.
+ ["\n", encodeXML],
+ ["\r", encodeXML],
+ ["\t", encodeXML],
+]);
+
+const encodingMap = new Map([
+ ["<", "&lt;"],
+ [">", "&gt;"],
+ ['"', "&quot;"],
+ ["&", "&amp;"],
+ ["\xA0", "&nbsp;"],
+ ["\n", "&#xA;"],
+ ["\r", "&#xD;"],
+ ["\t", "&#9;"],
+]);
+
+function encodingInfoForChar(c) {
+ var info = encodingInfoMap.get(c);
+ if (info) {
+ return info;
+ }
+ return encodeNone;
+}
+
+function encodingForChar(c, type) {
+ var info = encodingInfoForChar(c);
+ if (!info[type]) {
+ return c;
+ }
+ return encodingMap.get(c);
+}
+
+const doc = new DOMParser().parseFromString("<root></root>", "text/xml");
+const root = doc.documentElement;
+for (let i = 0; i < 255; ++i) {
+ let el = doc.createElement("span");
+ el.setAttribute("x", String.fromCharCode(i));
+ el.textContent = " ";
+ root.appendChild(el);
+}
+for (let type of ["xml", "xhtml", "htmlBasic", "html"]) {
+ let str = encoders[type](doc).encodeToString();
+ const prefix = '<root><span x="';
+ const suffix = '"> </span></root>';
+ Assert.ok(str.startsWith(prefix), `${type} serialization starts correctly`);
+ Assert.ok(str.endsWith(suffix), `${type} serialization ends correctly`);
+ str = str.substring(prefix.length, str.length - suffix.length);
+ let encodings = str.split('"> </span><span x="');
+ for (let i = 0; i < 255; ++i) {
+ let c = String.fromCharCode(i);
+ Assert.equal(
+ encodingForChar(c, type),
+ encodings[i],
+ `${type} encoding of char ${i} is correct`
+ );
+ }
+}
diff --git a/dom/base/test/unit/test_structuredcloneholder.js b/dom/base/test/unit/test_structuredcloneholder.js
new file mode 100644
index 0000000000..fd9afc7f03
--- /dev/null
+++ b/dom/base/test/unit/test_structuredcloneholder.js
@@ -0,0 +1,159 @@
+"use strict";
+
+const global = this;
+
+add_task(async function test_structuredCloneHolder() {
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI("http://example.com/"),
+ {}
+ );
+
+ let sandbox = Cu.Sandbox(principal);
+
+ const obj = { foo: [{ bar: "baz" }] };
+
+ let holder = new StructuredCloneHolder("", "", obj);
+
+ // Test same-compartment deserialization
+
+ let res = holder.deserialize(global, true);
+
+ notEqual(
+ res,
+ obj,
+ "Deserialized result is a different object from the original"
+ );
+
+ deepEqual(
+ res,
+ obj,
+ "Deserialized result is deeply equivalent to the original"
+ );
+
+ equal(
+ Cu.getObjectPrincipal(res),
+ Cu.getObjectPrincipal(global),
+ "Deserialized result has the correct principal"
+ );
+
+ // Test non-object-value round-trip.
+
+ equal(
+ new StructuredCloneHolder("", "", "foo").deserialize(global),
+ "foo",
+ "Round-tripping non-object values works as expected"
+ );
+
+ // Test cross-compartment deserialization
+
+ res = holder.deserialize(sandbox, true);
+
+ notEqual(
+ res,
+ obj,
+ "Cross-compartment-deserialized result is a different object from the original"
+ );
+
+ deepEqual(
+ res,
+ obj,
+ "Cross-compartment-deserialized result is deeply equivalent to the original"
+ );
+
+ equal(
+ Cu.getObjectPrincipal(res),
+ principal,
+ "Cross-compartment-deserialized result has the correct principal"
+ );
+
+ // Test message manager transportability
+
+ const MSG = "StructuredCloneHolder";
+
+ let resultPromise = new Promise(resolve => {
+ Services.ppmm.addMessageListener(MSG, resolve);
+ });
+
+ Services.cpmm.sendAsyncMessage(MSG, holder);
+
+ res = await resultPromise;
+
+ ok(
+ StructuredCloneHolder.isInstance(res.data),
+ "Sending structured clone holders through message managers works as expected"
+ );
+
+ deepEqual(
+ res.data.deserialize(global, true),
+ obj,
+ "Sending structured clone holders through message managers works as expected"
+ );
+
+ // Test that attempting to deserialize a neutered holder throws.
+
+ deepEqual(
+ holder.deserialize(global),
+ obj,
+ "Deserialized result is correct when discarding data"
+ );
+
+ Assert.throws(
+ () => holder.deserialize(global),
+ err => err.result == Cr.NS_ERROR_NOT_INITIALIZED,
+ "Attempting to deserialize neutered holder throws"
+ );
+
+ Assert.throws(
+ () => holder.deserialize(global, true),
+ err => err.result == Cr.NS_ERROR_NOT_INITIALIZED,
+ "Attempting to deserialize neutered holder throws"
+ );
+});
+
+// Test that X-rays passed to an exported function are serialized
+// through their exported wrappers.
+add_task(async function test_structuredCloneHolder_xray() {
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI("http://example.com/"),
+ {}
+ );
+
+ let sandbox1 = Cu.Sandbox(principal, { wantXrays: true });
+
+ let sandbox2 = Cu.Sandbox(principal, { wantXrays: true });
+ Cu.evalInSandbox(`this.x = {y: "z", get z() { return "q" }}`, sandbox2);
+
+ sandbox1.x = sandbox2.x;
+
+ let holder;
+ Cu.exportFunction(
+ function serialize(val) {
+ holder = new StructuredCloneHolder("", "", val, sandbox1);
+ },
+ sandbox1,
+ { defineAs: "serialize" }
+ );
+
+ Cu.evalInSandbox(`serialize(x)`, sandbox1);
+
+ const obj = { y: "z" };
+
+ let res = holder.deserialize(global);
+
+ deepEqual(
+ res,
+ obj,
+ "Deserialized result is deeply equivalent to the expected object"
+ );
+ deepEqual(
+ res,
+ sandbox2.x,
+ "Deserialized result is deeply equivalent to the X-ray-wrapped object"
+ );
+
+ equal(
+ Cu.getObjectPrincipal(res),
+ Cu.getObjectPrincipal(global),
+ "Deserialized result has the correct principal"
+ );
+});
diff --git a/dom/base/test/unit/test_thirdpartyutil.js b/dom/base/test/unit/test_thirdpartyutil.js
new file mode 100644
index 0000000000..777dc8dc62
--- /dev/null
+++ b/dom/base/test/unit/test_thirdpartyutil.js
@@ -0,0 +1,99 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test ThirdPartyUtil methods. See mozIThirdPartyUtil.
+
+var prefs = Services.prefs;
+
+// Since this test creates a TYPE_DOCUMENT channel via javascript, it will
+// end up using the wrong LoadInfo constructor. Setting this pref will disable
+// the ContentPolicyType assertion in the constructor.
+prefs.setBoolPref("network.loadinfo.skip_type_assertion", true);
+
+var NS_ERROR_INVALID_ARG = Cr.NS_ERROR_INVALID_ARG;
+
+function do_check_throws(f, result, stack) {
+ if (!stack) {
+ try {
+ // We might not have a 'Components' object.
+ stack = Components.stack.caller;
+ } catch (e) {}
+ }
+
+ try {
+ f();
+ } catch (exc) {
+ Assert.equal(exc.result, result);
+ return;
+ }
+ do_throw("expected " + result + " exception, none thrown", stack);
+}
+
+function run_test() {
+ let util = Cc["@mozilla.org/thirdpartyutil;1"].getService(
+ Ci.mozIThirdPartyUtil
+ );
+
+ // Create URIs and channels pointing to foo.com and bar.com.
+ // We will use these to put foo.com into first and third party contexts.
+ let spec1 = "http://foo.com/foo.html";
+ let spec2 = "http://bar.com/bar.html";
+ let uri1 = NetUtil.newURI(spec1);
+ let uri2 = NetUtil.newURI(spec2);
+ const contentPolicyType = Ci.nsIContentPolicy.TYPE_DOCUMENT;
+ let channel1 = NetUtil.newChannel({
+ uri: uri1,
+ loadUsingSystemPrincipal: true,
+ contentPolicyType,
+ });
+ NetUtil.newChannel({
+ uri: uri2,
+ loadUsingSystemPrincipal: true,
+ contentPolicyType,
+ });
+
+ // Create some file:// URIs.
+ let filespec1 = "file://foo.txt";
+ let filespec2 = "file://bar.txt";
+ let fileuri1 = NetUtil.newURI(filespec1);
+ let fileuri2 = NetUtil.newURI(filespec2);
+ NetUtil.newChannel({ uri: fileuri1, loadUsingSystemPrincipal: true });
+ NetUtil.newChannel({ uri: fileuri2, loadUsingSystemPrincipal: true });
+
+ // Test isThirdPartyURI.
+ Assert.ok(!util.isThirdPartyURI(uri1, uri1));
+ Assert.ok(util.isThirdPartyURI(uri1, uri2));
+ Assert.ok(util.isThirdPartyURI(uri2, uri1));
+ Assert.ok(!util.isThirdPartyURI(fileuri1, fileuri1));
+ Assert.ok(!util.isThirdPartyURI(fileuri1, fileuri2));
+ Assert.ok(util.isThirdPartyURI(uri1, fileuri1));
+ do_check_throws(function () {
+ util.isThirdPartyURI(uri1, null);
+ }, NS_ERROR_INVALID_ARG);
+ do_check_throws(function () {
+ util.isThirdPartyURI(null, uri1);
+ }, NS_ERROR_INVALID_ARG);
+ do_check_throws(function () {
+ util.isThirdPartyURI(null, null);
+ }, NS_ERROR_INVALID_ARG);
+
+ // We can't test isThirdPartyWindow since we can't really set up a window
+ // hierarchy. We leave that to mochitests.
+
+ // Test isThirdPartyChannel. As above, we can't test the bits that require
+ // a load context or window heirarchy. Because of bug 1259873, we assume
+ // that these are not third-party.
+ do_check_throws(function () {
+ util.isThirdPartyChannel(null);
+ }, NS_ERROR_INVALID_ARG);
+ Assert.ok(!util.isThirdPartyChannel(channel1));
+ Assert.ok(!util.isThirdPartyChannel(channel1, uri1));
+ Assert.ok(util.isThirdPartyChannel(channel1, uri2));
+
+ let httpchannel1 = channel1.QueryInterface(Ci.nsIHttpChannelInternal);
+ httpchannel1.forceAllowThirdPartyCookie = true;
+ Assert.ok(!util.isThirdPartyChannel(channel1));
+ Assert.ok(!util.isThirdPartyChannel(channel1, uri1));
+ Assert.ok(util.isThirdPartyChannel(channel1, uri2));
+}
diff --git a/dom/base/test/unit/test_treewalker.js b/dom/base/test/unit/test_treewalker.js
new file mode 100644
index 0000000000..a932965370
--- /dev/null
+++ b/dom/base/test/unit/test_treewalker.js
@@ -0,0 +1,23 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function run_test() {
+ test_treeWalker_currentNode();
+}
+
+// TEST CODE
+
+function test_treeWalker_currentNode() {
+ var XHTMLDocString = '<html xmlns="http://www.w3.org/1999/xhtml">';
+ XHTMLDocString += "<body><input/>input</body></html>";
+
+ var doc = ParseXML(XHTMLDocString);
+
+ var body = doc.getElementsByTagName("body")[0];
+ var filter = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT;
+ var walker = doc.createTreeWalker(body, filter, null);
+ walker.currentNode = body.firstChild;
+ walker.nextNode();
+}
diff --git a/dom/base/test/unit/test_xhr_document.js b/dom/base/test/unit/test_xhr_document.js
new file mode 100644
index 0000000000..aa96c283c0
--- /dev/null
+++ b/dom/base/test/unit/test_xhr_document.js
@@ -0,0 +1,45 @@
+/* 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/. */
+
+var { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
+
+var server = new HttpServer();
+server.start(-1);
+
+var docbody =
+ '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body></body></html>';
+
+function handler(metadata, response) {
+ var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+ let body = NetUtil.readInputStreamToString(
+ metadata.bodyInputStream,
+ metadata.bodyInputStream.available()
+ );
+ response.setStatusLine(metadata.httpVersion, 200, "OK");
+ response.write(body, body.length);
+}
+
+function run_test() {
+ do_test_pending();
+ server.registerPathHandler("/foo", handler);
+
+ var parser = new DOMParser();
+ let doc = parser.parseFromString(docbody, "text/html");
+ let xhr = new XMLHttpRequest();
+ xhr.onload = function () {
+ Assert.equal(xhr.responseText, docbody);
+ server.stop(do_test_finished);
+ };
+ xhr.onerror = function () {
+ Assert.equal(false, false);
+ server.stop(do_test_finished);
+ };
+ xhr.open(
+ "POST",
+ "http://localhost:" + server.identity.primaryPort + "/foo",
+ true
+ );
+ xhr.send(doc);
+}
diff --git a/dom/base/test/unit/test_xhr_origin_attributes.js b/dom/base/test/unit/test_xhr_origin_attributes.js
new file mode 100644
index 0000000000..26848af479
--- /dev/null
+++ b/dom/base/test/unit/test_xhr_origin_attributes.js
@@ -0,0 +1,53 @@
+let server = new HttpServer();
+server.start(-1);
+
+let body =
+ "<!DOCTYPE HTML><html><head><meta charset='utf-8'></head><body></body></html>";
+
+function handler(request, response) {
+ response.setStatusLine(request.httpVersion, 200, "Ok");
+ response.setHeader("Content-Type", "text/html", false);
+
+ if (!request.hasHeader("Cookie")) {
+ response.setHeader("Set-Cookie", "test", false);
+ ok(true);
+ } else {
+ ok(false);
+ }
+
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function run_test() {
+ do_test_pending();
+ server.registerPathHandler("/foo", handler);
+
+ let xhr = new XMLHttpRequest();
+ xhr.open(
+ "GET",
+ "http://localhost:" + server.identity.primaryPort + "/foo",
+ true
+ );
+ xhr.send(null);
+
+ xhr.onload = function () {
+ // We create another XHR to connect to the same site, but this time we
+ // specify with different origin attributes, which will make the XHR use a
+ // different cookie-jar than the previous one.
+ let xhr2 = new XMLHttpRequest();
+ xhr2.open(
+ "GET",
+ "http://localhost:" + server.identity.primaryPort + "/foo",
+ true
+ );
+ xhr2.setOriginAttributes({ userContextId: 1 });
+ xhr2.send(null);
+
+ let loadInfo = xhr2.channel.loadInfo;
+ Assert.equal(loadInfo.originAttributes.userContextId, 1);
+
+ xhr2.onload = function () {
+ server.stop(do_test_finished);
+ };
+ };
+}
diff --git a/dom/base/test/unit/test_xhr_standalone.js b/dom/base/test/unit/test_xhr_standalone.js
new file mode 100644
index 0000000000..94f2d7d642
--- /dev/null
+++ b/dom/base/test/unit/test_xhr_standalone.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test setting .responseType and .withCredentials is allowed
+// in non-window non-Worker context
+
+function run_test() {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "data:,", false);
+ var exceptionThrown = false;
+ try {
+ xhr.responseType = "";
+ xhr.withCredentials = false;
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ Assert.equal(false, exceptionThrown);
+}
diff --git a/dom/base/test/unit/test_xml_parser.js b/dom/base/test/unit/test_xml_parser.js
new file mode 100644
index 0000000000..0d6675fdab
--- /dev/null
+++ b/dom/base/test/unit/test_xml_parser.js
@@ -0,0 +1,48 @@
+function run_test() {
+ for (var i = 0; i < tests.length && tests[i][0]; ++i) {
+ if (!tests[i][0].call()) {
+ do_throw(tests[i][1]);
+ }
+ }
+}
+
+var tests = [
+ [test1, "Unable to parse basic XML document"],
+ [test2, "ParseXML doesn't return Document"],
+ [test3, "ParseXML return value's documentElement is not Element"],
+ [test4, ""],
+ [test5, ""],
+ [test6, ""],
+ [null],
+];
+
+function test1() {
+ return ParseXML("<root/>");
+}
+
+function test2() {
+ return ChromeUtils.getClassName(ParseXML("<root/>")) === "XMLDocument";
+}
+
+function test3() {
+ return Element.isInstance(ParseXML("<root/>").documentElement);
+}
+
+function test4() {
+ var doc = ParseXML("<root/>");
+ Assert.equal(doc.documentElement.namespaceURI, null);
+ return true;
+}
+
+function test5() {
+ var doc = ParseXML("<root xmlns=''/>");
+ Assert.equal(doc.documentElement.namespaceURI, null);
+ return true;
+}
+
+function test6() {
+ var doc = ParseXML("<root xmlns='ns1'/>");
+ Assert.notEqual(doc.documentElement.namespaceURI, null);
+ Assert.equal(doc.documentElement.namespaceURI, "ns1");
+ return true;
+}
diff --git a/dom/base/test/unit/test_xml_serializer.js b/dom/base/test/unit/test_xml_serializer.js
new file mode 100644
index 0000000000..11fbb02f6f
--- /dev/null
+++ b/dom/base/test/unit/test_xml_serializer.js
@@ -0,0 +1,421 @@
+// The xml serializer uses the default line break of the plateform.
+// So we need to know the value of this default line break, in order
+// to build correctly the reference strings for tests.
+// This variable will contain this value.
+var LB;
+
+function run_test() {
+ if (mozinfo.os == "win") {
+ LB = "\r\n";
+ } else {
+ LB = "\n";
+ }
+
+ for (var i = 0; i < tests.length && tests[i]; ++i) {
+ tests[i].call();
+ }
+}
+
+var tests = [
+ test1,
+ test2,
+ test3,
+ test4,
+ test5,
+ test6,
+ test7,
+ test8,
+ test9,
+ test10,
+ null,
+];
+
+function testString(str) {
+ Assert.equal(roundtrip(str), str);
+}
+
+function test1() {
+ // Basic round-tripping which we expect to hand back the same text
+ // as we passed in (not strictly required for correctness in some of
+ // those cases, but best for readability of serializer output)
+ testString("<root/>");
+ testString("<root><child/></root>");
+ testString('<root xmlns=""/>');
+ testString('<root xml:lang="en"/>');
+ testString('<root xmlns="ns1"><child xmlns="ns2"/></root>');
+ testString('<root xmlns="ns1"><child xmlns=""/></root>');
+ testString('<a:root xmlns:a="ns1"><child/></a:root>');
+ testString('<a:root xmlns:a="ns1"><a:child/></a:root>');
+ testString('<a:root xmlns:a="ns1"><b:child xmlns:b="ns1"/></a:root>');
+ testString('<a:root xmlns:a="ns1"><a:child xmlns:a="ns2"/></a:root>');
+ testString(
+ '<a:root xmlns:a="ns1"><b:child xmlns:b="ns1" b:attr=""/></a:root>'
+ );
+}
+
+function test2() {
+ // Test setting of "xmlns" attribute in the null namespace
+
+ // XXXbz are these tests needed? What should happen here? These
+ // may be bogus.
+
+ // Setting random "xmlns" attribute
+ var doc = ParseXML('<root xmlns="ns1"/>');
+ doc.documentElement.setAttribute("xmlns", "ns2");
+ do_check_serialize(doc);
+}
+
+function test3() {
+ // Test basic appending of kids. Again, we're making assumptions
+ // about how our serializer will serialize simple DOMs.
+ var doc = ParseXML('<root xmlns="ns1"/>');
+ var root = doc.documentElement;
+ var child = doc.createElementNS("ns2", "child");
+ root.appendChild(child);
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1"><child xmlns="ns2"/></root>'
+ );
+
+ doc = ParseXML('<root xmlns="ns1"/>');
+ root = doc.documentElement;
+ child = doc.createElementNS("ns2", "prefix:child");
+ root.appendChild(child);
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1"><prefix:child xmlns:prefix="ns2"/></root>'
+ );
+
+ doc = ParseXML('<prefix:root xmlns:prefix="ns1"/>');
+ root = doc.documentElement;
+ child = doc.createElementNS("ns2", "prefix:child");
+ root.appendChild(child);
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<prefix:root xmlns:prefix="ns1"><a0:child xmlns:a0="ns2"/>' +
+ "</prefix:root>"
+ );
+}
+
+function test4() {
+ // setAttributeNS tests
+
+ var doc = ParseXML('<root xmlns="ns1"/>');
+ var root = doc.documentElement;
+ root.setAttributeNS("ns1", "prefix:local", "val");
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1" prefix:local="val" xmlns:prefix="ns1"/>'
+ );
+
+ doc = ParseXML('<prefix:root xmlns:prefix="ns1"/>');
+ root = doc.documentElement;
+ root.setAttributeNS("ns1", "local", "val");
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<prefix:root xmlns:prefix="ns1" prefix:local="val"/>'
+ );
+
+ doc = ParseXML('<root xmlns="ns1"/>');
+ root = doc.documentElement;
+ root.setAttributeNS("ns2", "local", "val");
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1" a0:local="val" xmlns:a0="ns2"/>'
+ );
+
+ // Handling of prefix-generation for non-null-namespace attributes
+ // which have the same namespace as the current default namespace
+ // (bug 301260).
+ doc = ParseXML('<root xmlns="ns1"/>');
+ root = doc.documentElement;
+ root.setAttributeNS("ns1", "local", "val");
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1" a0:local="val" xmlns:a0="ns1"/>'
+ );
+
+ // Tree-walking test
+ doc = ParseXML(
+ '<root xmlns="ns1" xmlns:a="ns2">' +
+ '<child xmlns:b="ns2" xmlns:a="ns3">' +
+ "<child2/></child></root>"
+ );
+ root = doc.documentElement;
+ var node = root.firstChild.firstChild;
+ node.setAttributeNS("ns4", "l1", "v1");
+ node.setAttributeNS("ns4", "p2:l2", "v2");
+ node.setAttributeNS("", "l3", "v3");
+ node.setAttributeNS("ns3", "l4", "v4");
+ node.setAttributeNS("ns3", "p5:l5", "v5");
+ node.setAttributeNS("ns3", "a:l6", "v6");
+ node.setAttributeNS("ns2", "l7", "v7");
+ node.setAttributeNS("ns2", "p8:l8", "v8");
+ node.setAttributeNS("ns2", "b:l9", "v9");
+ node.setAttributeNS("ns2", "a:l10", "v10");
+ node.setAttributeNS("ns1", "a:l11", "v11");
+ node.setAttributeNS("ns1", "b:l12", "v12");
+ node.setAttributeNS("ns1", "l13", "v13");
+ do_check_serialize(doc);
+ // Note: we end up with "a2" as the prefix on "l11" and "l12" because we use
+ // "a1" earlier, and discard it in favor of something we get off the
+ // namespace stack, apparently
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1" xmlns:a="ns2">' +
+ '<child xmlns:b="ns2" xmlns:a="ns3">' +
+ '<child2 a0:l1="v1" xmlns:a0="ns4"' +
+ ' a0:l2="v2"' +
+ ' l3="v3"' +
+ ' a:l4="v4"' +
+ ' a:l5="v5"' +
+ ' a:l6="v6"' +
+ ' b:l7="v7"' +
+ ' b:l8="v8"' +
+ ' b:l9="v9"' +
+ ' b:l10="v10"' +
+ ' a2:l11="v11" xmlns:a2="ns1"' +
+ ' a2:l12="v12"' +
+ ' a2:l13="v13"/></child></root>'
+ );
+}
+
+function test5() {
+ // Handling of kids in the null namespace when the default is a
+ // different namespace (bug 301260).
+ var doc = ParseXML('<root xmlns="ns1"/>');
+ var child = doc.createElement("child");
+ doc.documentElement.appendChild(child);
+ do_check_serialize(doc);
+ Assert.equal(SerializeXML(doc), '<root xmlns="ns1"><child xmlns=""/></root>');
+}
+
+function test6() {
+ // Handling of not using a namespace prefix (or default namespace!)
+ // that's not bound to our namespace in our scope (bug 301260).
+ var doc = ParseXML('<prefix:root xmlns:prefix="ns1"/>');
+ var root = doc.documentElement;
+ var child1 = doc.createElementNS("ns2", "prefix:child1");
+ var child2 = doc.createElementNS("ns1", "prefix:child2");
+ child1.appendChild(child2);
+ root.appendChild(child1);
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<prefix:root xmlns:prefix="ns1"><a0:child1 xmlns:a0="ns2">' +
+ "<prefix:child2/></a0:child1></prefix:root>"
+ );
+
+ doc = ParseXML(
+ '<root xmlns="ns1"><prefix:child1 xmlns:prefix="ns2"/></root>'
+ );
+ root = doc.documentElement;
+ child1 = root.firstChild;
+ child2 = doc.createElementNS("ns1", "prefix:child2");
+ child1.appendChild(child2);
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1"><prefix:child1 xmlns:prefix="ns2">' +
+ "<child2/></prefix:child1></root>"
+ );
+
+ doc = ParseXML(
+ '<prefix:root xmlns:prefix="ns1">' +
+ '<prefix:child1 xmlns:prefix="ns2"/></prefix:root>'
+ );
+ root = doc.documentElement;
+ child1 = root.firstChild;
+ child2 = doc.createElementNS("ns1", "prefix:child2");
+ child1.appendChild(child2);
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<prefix:root xmlns:prefix="ns1"><prefix:child1 xmlns:prefix="ns2">' +
+ '<a0:child2 xmlns:a0="ns1"/></prefix:child1></prefix:root>'
+ );
+
+ doc = ParseXML('<root xmlns="ns1"/>');
+ root = doc.documentElement;
+ child1 = doc.createElementNS("ns2", "child1");
+ child2 = doc.createElementNS("ns1", "child2");
+ child1.appendChild(child2);
+ root.appendChild(child1);
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="ns1"><child1 xmlns="ns2"><child2 xmlns="ns1"/>' +
+ "</child1></root>"
+ );
+}
+
+function test7() {
+ // Handle xmlns attribute declaring a default namespace on a non-namespaced
+ // element (bug 326994).
+ var doc = ParseXML('<root xmlns=""/>');
+ var root = doc.documentElement;
+ root.setAttributeNS(
+ "http://www.w3.org/2000/xmlns/",
+ "xmlns",
+ "http://www.w3.org/1999/xhtml"
+ );
+ do_check_serialize(doc);
+ Assert.equal(SerializeXML(doc), "<root/>");
+
+ doc = ParseXML('<root xmlns=""><child1/></root>');
+ root = doc.documentElement;
+ root.setAttributeNS(
+ "http://www.w3.org/2000/xmlns/",
+ "xmlns",
+ "http://www.w3.org/1999/xhtml"
+ );
+ do_check_serialize(doc);
+ Assert.equal(SerializeXML(doc), "<root><child1/></root>");
+
+ doc = ParseXML(
+ '<root xmlns="http://www.w3.org/1999/xhtml">' +
+ '<child1 xmlns=""><child2/></child1></root>'
+ );
+ root = doc.documentElement;
+
+ var child1 = root.firstChild;
+ child1.setAttributeNS(
+ "http://www.w3.org/2000/xmlns/",
+ "xmlns",
+ "http://www.w3.org/1999/xhtml"
+ );
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="http://www.w3.org/1999/xhtml"><child1 xmlns="">' +
+ "<child2/></child1></root>"
+ );
+
+ doc = ParseXML(
+ '<root xmlns="http://www.w3.org/1999/xhtml">' +
+ '<child1 xmlns="">' +
+ '<child2 xmlns="http://www.w3.org/1999/xhtml"></child2>' +
+ "</child1></root>"
+ );
+ root = doc.documentElement;
+ child1 = root.firstChild;
+ var child2 = child1.firstChild;
+ child1.setAttributeNS(
+ "http://www.w3.org/2000/xmlns/",
+ "xmlns",
+ "http://www.w3.org/1999/xhtml"
+ );
+ child2.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "");
+ do_check_serialize(doc);
+ Assert.equal(
+ SerializeXML(doc),
+ '<root xmlns="http://www.w3.org/1999/xhtml"><child1 xmlns="">' +
+ '<a0:child2 xmlns:a0="http://www.w3.org/1999/xhtml" xmlns=""></a0:child2></child1></root>'
+ );
+}
+
+function test8() {
+ // Test behavior of serializing with a given charset.
+ var str1 = '<?xml version="1.0" encoding="windows-1252"?>' + LB + "<root/>";
+ var str2 = '<?xml version="1.0" encoding="UTF-8"?>' + LB + "<root/>";
+ var doc1 = ParseXML(str1);
+ var doc2 = ParseXML(str2);
+
+ var p = Pipe();
+ DOMSerializer().serializeToStream(doc1, p.outputStream, "windows-1252");
+ p.outputStream.close();
+ Assert.equal(ScriptableInput(p).read(-1), str1);
+
+ p = Pipe();
+ DOMSerializer().serializeToStream(doc2, p.outputStream, "windows-1252");
+ p.outputStream.close();
+ Assert.equal(ScriptableInput(p).read(-1), str1);
+
+ p = Pipe();
+ DOMSerializer().serializeToStream(doc1, p.outputStream, "UTF-8");
+ p.outputStream.close();
+ Assert.equal(ScriptableInput(p).read(-1), str2);
+
+ p = Pipe();
+ DOMSerializer().serializeToStream(doc2, p.outputStream, "UTF-8");
+ p.outputStream.close();
+ Assert.equal(ScriptableInput(p).read(-1), str2);
+}
+
+function test9() {
+ // Test behavior of serializing between given charsets, using
+ // windows-1252-representable text.
+ var contents =
+ // eslint-disable-next-line no-useless-concat
+ "<root>" + "\u00BD + \u00BE == \u00BD\u00B2 + \u00BC + \u00BE" + "</root>";
+ var str1 = '<?xml version="1.0" encoding="windows-1252"?>' + LB + contents;
+ var str2 = '<?xml version="1.0" encoding="UTF-8"?>' + LB + contents;
+ var str3 = '<?xml version="1.0" encoding="UTF-16"?>' + LB + contents;
+ var doc1 = ParseXML(str1);
+ var doc2 = ParseXML(str2);
+ var doc3 = ParseXML(str3);
+
+ checkSerialization(doc1, "windows-1252", str1);
+ checkSerialization(doc2, "windows-1252", str1);
+ checkSerialization(doc3, "windows-1252", str1);
+
+ checkSerialization(doc1, "UTF-8", str2);
+ checkSerialization(doc2, "UTF-8", str2);
+ checkSerialization(doc3, "UTF-8", str2);
+
+ checkSerialization(doc1, "UTF-16", str2);
+ checkSerialization(doc2, "UTF-16", str2);
+ checkSerialization(doc3, "UTF-16", str2);
+}
+
+function test10() {
+ // Test behavior of serializing between given charsets, using
+ // Unicode characters (XXX but only BMP ones because I don't know
+ // how to create one with non-BMP characters, either with JS strings
+ // or using DOM APIs).
+ var contents =
+ "<root>" +
+ "AZaz09 \u007F " + // U+000000 to U+00007F
+ "\u0080 \u0398 \u03BB \u0725 " + // U+000080 to U+0007FF
+ "\u0964 \u0F5F \u20AC \uFFFB" + // U+000800 to U+00FFFF
+ "</root>";
+ var str1 = '<?xml version="1.0" encoding="UTF-8"?>' + LB + contents;
+ var str2 = '<?xml version="1.0" encoding="UTF-16"?>' + LB + contents;
+ var doc1 = ParseXML(str1);
+ var doc2 = ParseXML(str2);
+
+ checkSerialization(doc1, "UTF8", str1);
+ checkSerialization(doc2, "UTF8", str1);
+
+ checkSerialization(doc1, "UTF-16", str1);
+ checkSerialization(doc2, "UTF-16", str1);
+}
+
+function checkSerialization(doc, toCharset, expectedString) {
+ var p = Pipe();
+ DOMSerializer().serializeToStream(doc, p.outputStream, toCharset);
+ p.outputStream.close();
+
+ var inCharset = toCharset == "UTF-16" ? "UTF-8" : toCharset;
+ var cin = C["@mozilla.org/intl/converter-input-stream;1"].createInstance(
+ I.nsIConverterInputStream
+ );
+ cin.init(p.inputStream, inCharset, 1024, 0x0);
+
+ // compare the first expectedString.length characters for equality
+ var outString = {};
+ var count = cin.readString(expectedString.length, outString);
+ Assert.equal(count, expectedString.length);
+ Assert.equal(outString.value, expectedString);
+
+ // if there's anything more in the stream, it's a bug
+ Assert.equal(0, cin.readString(1, outString));
+ Assert.equal(outString.value, "");
+}
diff --git a/dom/base/test/unit/test_xmlserializer.js b/dom/base/test/unit/test_xmlserializer.js
new file mode 100644
index 0000000000..86f926def5
--- /dev/null
+++ b/dom/base/test/unit/test_xmlserializer.js
@@ -0,0 +1,179 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
+/* 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/. */
+
+async function xmlEncode(aFile, aFlags, aCharset) {
+ if (aFlags == undefined) {
+ aFlags = 0;
+ }
+ if (aCharset == undefined) {
+ aCharset = "UTF-8";
+ }
+
+ var doc = await do_parse_document(aFile, "text/xml");
+
+ var encoder = Cu.createDocumentEncoder("text/xml");
+ encoder.setCharset(aCharset);
+ encoder.init(doc, "text/xml", aFlags);
+ return encoder.encodeToString();
+}
+
+add_task(async function test_encoding() {
+ var result, expected;
+ const de = Ci.nsIDocumentEncoder;
+
+ result = await xmlEncode("1_original.xml", de.OutputLFLineBreak);
+ expected = loadContentFile("1_result.xml");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode("2_original.xml", de.OutputLFLineBreak);
+ expected = loadContentFile("2_result_1.xml");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode("2_original.xml", de.OutputCRLineBreak);
+ expected = expected.replace(/\n/g, "\r");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "2_original.xml",
+ de.OutputLFLineBreak | de.OutputCRLineBreak
+ );
+ expected = expected.replace(/\r/gm, "\r\n");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "2_original.xml",
+ de.OutputLFLineBreak | de.OutputFormatted
+ );
+ expected = loadContentFile("2_result_2.xml");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "2_original.xml",
+ de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap
+ );
+ expected = loadContentFile("2_result_3.xml");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "2_original.xml",
+ de.OutputLFLineBreak | de.OutputWrap
+ );
+ expected = loadContentFile("2_result_4.xml");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "3_original.xml",
+ de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap
+ );
+ expected = loadContentFile("3_result.xml");
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "3_original.xml",
+ de.OutputLFLineBreak | de.OutputWrap
+ );
+ expected = loadContentFile("3_result_2.xml");
+ Assert.equal(expected, result);
+
+ // tests on namespaces
+ var doc = await do_parse_document("4_original.xml", "text/xml");
+
+ var encoder = Cu.createDocumentEncoder("text/xml");
+ encoder.setCharset("UTF-8");
+ encoder.init(doc, "text/xml", de.OutputLFLineBreak);
+
+ result = encoder.encodeToString();
+ expected = loadContentFile("4_result_1.xml");
+ Assert.equal(expected, result);
+
+ encoder.setNode(doc.documentElement.childNodes[9]);
+ result = encoder.encodeToString();
+ expected = loadContentFile("4_result_2.xml");
+ Assert.equal(expected, result);
+
+ encoder.setNode(doc.documentElement.childNodes[7].childNodes[1]);
+ result = encoder.encodeToString();
+ expected = loadContentFile("4_result_3.xml");
+ Assert.equal(expected, result);
+
+ encoder.setNode(doc.documentElement.childNodes[11].childNodes[1]);
+ result = encoder.encodeToString();
+ expected = loadContentFile("4_result_4.xml");
+ Assert.equal(expected, result);
+
+ encoder.setCharset("UTF-8");
+ // it doesn't support this flags
+ encoder.init(
+ doc,
+ "text/xml",
+ de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap
+ );
+ encoder.setWrapColumn(40);
+ result = encoder.encodeToString();
+ expected = loadContentFile("4_result_5.xml");
+ Assert.equal(expected, result);
+
+ encoder.init(doc, "text/xml", de.OutputLFLineBreak | de.OutputWrap);
+ encoder.setWrapColumn(40);
+ result = encoder.encodeToString();
+ expected = loadContentFile("4_result_6.xml");
+ Assert.equal(expected, result);
+});
+
+// OutputRaw should cause OutputWrap and OutputFormatted to be ignored.
+// Check by encoding each test file and making sure the result matches what
+// was fed in.
+add_task(async function test_outputRaw() {
+ let result, expected;
+ const de = Ci.nsIDocumentEncoder;
+
+ expected = loadContentFile("2_original.xml");
+ result = await xmlEncode(
+ "2_original.xml",
+ de.OutputRaw | de.OutputLFLineBreak | de.OutputWrap
+ );
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "2_original.xml",
+ de.OutputRaw | de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap
+ );
+ Assert.equal(expected, result);
+
+ expected = loadContentFile("3_original.xml");
+ result = await xmlEncode(
+ "3_original.xml",
+ de.OutputRaw | de.OutputLFLineBreak | de.OutputWrap
+ );
+ Assert.equal(expected, result);
+
+ result = await xmlEncode(
+ "3_original.xml",
+ de.OutputRaw | de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap
+ );
+ Assert.equal(expected, result);
+
+ expected = loadContentFile("4_original.xml");
+ let doc = await do_parse_document("4_original.xml", "text/xml");
+ let encoder = Cu.createDocumentEncoder("text/xml");
+ encoder.setCharset("UTF-8");
+ encoder.init(
+ doc,
+ "text/xml",
+ de.OutputRaw | de.OutputLFLineBreak | de.OutputWrap
+ );
+ encoder.setWrapColumn(40);
+ result = encoder.encodeToString();
+ Assert.equal(expected, result);
+
+ encoder.init(
+ doc,
+ "text/xml",
+ de.OutputRaw | de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap
+ );
+ encoder.setWrapColumn(40);
+ result = encoder.encodeToString();
+ Assert.equal(expected, result);
+});
diff --git a/dom/base/test/unit/xpcshell.ini b/dom/base/test/unit/xpcshell.ini
new file mode 100644
index 0000000000..ef9b3b818f
--- /dev/null
+++ b/dom/base/test/unit/xpcshell.ini
@@ -0,0 +1,70 @@
+[DEFAULT]
+head = head_utilities.js
+support-files =
+ 1_original.xml
+ 1_result.xml
+ 2_original.xml
+ 2_result_1.xml
+ 2_result_2.xml
+ 2_result_3.xml
+ 2_result_4.xml
+ 3_original.xml
+ 3_result.xml
+ 3_result_2.xml
+ 4_original.xml
+ 4_result_1.xml
+ 4_result_2.xml
+ 4_result_3.xml
+ 4_result_4.xml
+ 4_result_5.xml
+ 4_result_6.xml
+ empty_document.xml
+ isequalnode_data.xml
+ nodelist_data_1.xml
+ nodelist_data_2.xhtml
+ test_delete_range.xml
+
+[test_blockParsing.js]
+skip-if =
+ debug # We fail an assertion if we block parsing on a self-closing element
+ toolkit == 'android'
+ appname == 'thunderbird' # The test needs to run without e10s, can't do that.
+[test_bug553888.js]
+[test_bug737966.js]
+[test_error_codes.js]
+run-sequentially = Hardcoded 4444 port.
+# Bug 1018414: hardcoded localhost doesn't work properly on some OS X installs
+skip-if = os == 'mac'
+[test_htmlserializer.js]
+[test_isequalnode.js]
+head = head_xml.js
+[test_nodelist.js]
+head = head_xml.js
+[test_normalize.js]
+head = head_xml.js
+[test_range.js]
+head = head_xml.js
+[test_serializers_entities.js]
+[test_serializers_entities_in_attr.js]
+[test_structuredcloneholder.js]
+[test_thirdpartyutil.js]
+[test_treewalker.js]
+head = head_xml.js
+[test_xhr_document.js]
+[test_xhr_standalone.js]
+[test_xhr_origin_attributes.js]
+[test_xml_parser.js]
+head = head_xml.js
+[test_xml_serializer.js]
+head = head_xml.js
+[test_xmlserializer.js]
+[test_cancelPrefetch.js]
+[test_chromeutils_base64.js]
+[test_chromeutils_getXPCOMErrorName.js]
+[test_chromeutils_shallowclone.js]
+[test_generate_xpath.js]
+head = head_xml.js
+[test_js_dev_error_interceptor.js]
+# This feature is implemented only in NIGHTLY.
+run-if = nightly_build
+
diff --git a/dom/base/test/unit_ipc/test_bug553888_wrap.js b/dom/base/test/unit_ipc/test_bug553888_wrap.js
new file mode 100644
index 0000000000..0dede092e2
--- /dev/null
+++ b/dom/base/test/unit_ipc/test_bug553888_wrap.js
@@ -0,0 +1,3 @@
+function run_test() {
+ run_test_in_child("../unit/test_bug553888.js");
+}
diff --git a/dom/base/test/unit_ipc/test_xhr_document_ipc.js b/dom/base/test/unit_ipc/test_xhr_document_ipc.js
new file mode 100644
index 0000000000..1f65969b27
--- /dev/null
+++ b/dom/base/test/unit_ipc/test_xhr_document_ipc.js
@@ -0,0 +1,3 @@
+function run_test() {
+ run_test_in_child("../unit/test_xhr_document.js");
+}
diff --git a/dom/base/test/unit_ipc/xpcshell.ini b/dom/base/test/unit_ipc/xpcshell.ini
new file mode 100644
index 0000000000..e02cfb4e45
--- /dev/null
+++ b/dom/base/test/unit_ipc/xpcshell.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+head =
+skip-if = toolkit == 'android' || socketprocess_networking
+support-files =
+ !/dom/base/test/unit/test_bug553888.js
+ !/dom/base/test/unit/test_xhr_document.js
+
+[test_bug553888_wrap.js]
+prefs = network.allow_raw_sockets_in_content_processes=true
+[test_xhr_document_ipc.js]
+prefs = network.allow_raw_sockets_in_content_processes=true
diff --git a/dom/base/test/useractivation/file_clipboard_common.js b/dom/base/test/useractivation/file_clipboard_common.js
new file mode 100644
index 0000000000..fe172e52c8
--- /dev/null
+++ b/dom/base/test/useractivation/file_clipboard_common.js
@@ -0,0 +1,505 @@
+// This test is called from both test_clipboard_editor.html and test_clipboard_noeditor.html
+// This is to test that the code works both in the presence of a contentEditable node, and in the absense of one
+var WATCH_TIMEOUT = 300;
+
+// Some global variables to make the debug messages easier to track down
+var gTestN0 = 0,
+ gTestN1 = 0,
+ gTestN2 = 0;
+function testLoc() {
+ return " " + gTestN0 + " - " + gTestN1 + " - " + gTestN2;
+}
+
+// Listen for cut & copy events
+var gCopyCount = 0,
+ gCutCount = 0;
+document.addEventListener("copy", function () {
+ gCopyCount++;
+});
+document.addEventListener("cut", function () {
+ gCutCount++;
+});
+
+// Helper methods
+function selectNode(aSelector, aCb) {
+ var dn = document.querySelector(aSelector);
+ var range = document.createRange();
+ range.selectNodeContents(dn);
+ window.getSelection().removeAllRanges();
+ window.getSelection().addRange(range);
+ if (aCb) {
+ aCb();
+ }
+}
+
+function selectInputNode(aSelector, aCb) {
+ var dn = document.querySelector(aSelector);
+ synthesizeMouse(dn, 10, 10, {});
+ SimpleTest.executeSoon(function () {
+ synthesizeKey("A", { accelKey: true });
+ // Clear the user activation state which is set from synthesized mouse and
+ // key event.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ SimpleTest.executeSoon(aCb);
+ });
+}
+
+// Callback functions for attaching to the button
+function execCommand(aCommand, aShouldSucceed, aAsync = false) {
+ var cb = function (e) {
+ e.preventDefault();
+ document.removeEventListener("keydown", cb);
+
+ if (aAsync) {
+ setTimeout(() => {
+ is(
+ aShouldSucceed,
+ document.execCommand(aCommand),
+ "Keydown caused " + aCommand + " invocation" + testLoc()
+ );
+ }, 0);
+ } else {
+ is(
+ aShouldSucceed,
+ document.execCommand(aCommand),
+ "Keydown caused " + aCommand + " invocation" + testLoc()
+ );
+ }
+ };
+ return cb;
+}
+
+// The basic test set. Tries to cut/copy everything
+function cutCopyAll(
+ aDoCut,
+ aDoCopy,
+ aDone,
+ aNegate,
+ aClipOverride,
+ aJustClipboardNegate
+) {
+ var execCommandAlwaysSucceed = !!(aClipOverride || aJustClipboardNegate);
+
+ function waitForClipboard(aCond, aSetup, aNext, aNegateOne) {
+ if (aClipOverride) {
+ aCond = aClipOverride;
+ aNegateOne = false;
+ }
+ if (aNegate || aNegateOne || aJustClipboardNegate) {
+ SimpleTest.waitForClipboard(
+ null,
+ aSetup,
+ aNext,
+ aNext,
+ "text/plain",
+ WATCH_TIMEOUT,
+ true
+ );
+ } else {
+ SimpleTest.waitForClipboard(aCond, aSetup, aNext, aNext);
+ }
+ }
+
+ function validateCutCopy(aExpectedCut, aExpectedCopy) {
+ if (aNegate) {
+ aExpectedCut = aExpectedCopy = 0;
+ } // When we are negating - we always expect callbacks not to be run
+
+ is(
+ aExpectedCut,
+ gCutCount,
+ (aExpectedCut > 0
+ ? "Expect cut callback to run"
+ : "Expect cut callback not to run") + testLoc()
+ );
+ is(
+ aExpectedCopy,
+ gCopyCount,
+ (aExpectedCopy > 0
+ ? "Expect copy callback to run"
+ : "Expect copy callback not to run") + testLoc()
+ );
+ gCutCount = gCopyCount = 0;
+ }
+
+ function step(n) {
+ function nextStep() {
+ step(n + 1);
+ }
+
+ // Reset the user activation state before running next test.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+
+ document.querySelector("span").textContent = "span text";
+ document.querySelector("input[type=text]").value = "text text";
+ document.querySelector("input[type=password]").value = "password text";
+ document.querySelector("textarea").value = "textarea text";
+
+ var contentEditableNode = document.querySelector(
+ "div[contentEditable=true]"
+ );
+ if (contentEditableNode) {
+ contentEditableNode.textContent = "contenteditable text";
+ }
+
+ gTestN2 = n;
+ switch (n) {
+ case 0:
+ // copy on readonly selection
+ selectNode("span");
+ waitForClipboard(
+ "span text",
+ function () {
+ aDoCopy(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 1:
+ validateCutCopy(0, 1);
+
+ // cut on readonly selection
+ selectNode("span");
+
+ waitForClipboard(
+ "span text",
+ function () {
+ aDoCut(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 2:
+ validateCutCopy(1, 0);
+
+ // copy on textbox selection
+ selectInputNode("input[type=text]", nextStep);
+ return;
+
+ case 3:
+ waitForClipboard(
+ "text text",
+ function () {
+ selectInputNode("input[type=text]", function () {
+ aDoCopy(true);
+ });
+ },
+ nextStep
+ );
+ return;
+
+ case 4:
+ validateCutCopy(0, 1);
+
+ // cut on textbox selection
+ selectInputNode("input[type=text]", nextStep);
+ return;
+
+ case 5:
+ waitForClipboard(
+ "text text",
+ function () {
+ aDoCut(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 6:
+ validateCutCopy(1, 0);
+
+ // copy on password selection
+ selectInputNode("input[type=password]", nextStep);
+ return;
+
+ case 7:
+ waitForClipboard(
+ null,
+ function () {
+ aDoCopy(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 8:
+ validateCutCopy(0, 1);
+
+ // cut on password selection
+ selectInputNode("input[type=password]", nextStep);
+ return;
+
+ case 9:
+ waitForClipboard(
+ null,
+ function () {
+ aDoCut(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 10:
+ validateCutCopy(1, 0);
+
+ // copy on textarea selection
+ selectInputNode("textarea", nextStep);
+ return;
+
+ case 11:
+ waitForClipboard(
+ "textarea text",
+ function () {
+ aDoCopy(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 12:
+ validateCutCopy(0, 1);
+
+ // cut on password selection
+ selectInputNode("textarea", nextStep);
+ return;
+
+ case 13:
+ waitForClipboard(
+ "textarea text",
+ function () {
+ aDoCut(true);
+ },
+ nextStep
+ );
+ return;
+
+ case 14:
+ validateCutCopy(1, 0);
+
+ // copy on no selection
+ document.querySelector("textarea").blur();
+
+ waitForClipboard(
+ null,
+ function () {
+ aDoCopy(true);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 15:
+ validateCutCopy(0, 1);
+
+ // cut on no selection
+ waitForClipboard(
+ null,
+ function () {
+ aDoCut(execCommandAlwaysSucceed);
+ },
+ nextStep,
+ true
+ );
+ return;
+
+ case 16:
+ validateCutCopy(1, 0);
+
+ if (!document.querySelector("div[contentEditable=true]")) {
+ // We're done! (no contentEditable node!)
+ step(-1);
+ return;
+ }
+ break;
+
+ case 17:
+ // copy on contenteditable selection
+ waitForClipboard(
+ "contenteditable text",
+ function () {
+ selectNode("div[contentEditable=true]", function () {
+ aDoCopy(true);
+ });
+ },
+ nextStep
+ );
+ return;
+
+ case 18:
+ validateCutCopy(0, 1);
+ break;
+
+ case 19:
+ // cut on contenteditable selection
+ waitForClipboard(
+ "contenteditable text",
+ function () {
+ selectNode("div[contentEditable=true]", function () {
+ aDoCut(true);
+ });
+ },
+ nextStep
+ );
+ return;
+
+ case 20:
+ validateCutCopy(1, 0);
+ break;
+
+ default:
+ aDone();
+ return;
+ }
+
+ SimpleTest.executeSoon(function () {
+ step(n + 1);
+ });
+ }
+
+ step(0);
+}
+
+function allMechanisms(aCb, aClipOverride, aNegateAll) {
+ function testStep(n) {
+ gTestN1 = n;
+ switch (n) {
+ /** Test for Bug 1012662 **/
+ case 0:
+ // Keyboard issued
+ cutCopyAll(
+ function docut(aSucc) {
+ synthesizeKey("x", { accelKey: true });
+ },
+ function docopy(aSucc) {
+ synthesizeKey("c", { accelKey: true });
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ false,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ case 1:
+ // Button issued
+ cutCopyAll(
+ function docut(aSucc) {
+ document.addEventListener("keydown", execCommand("cut", aSucc));
+ sendString("Q");
+ },
+ function docopy(aSucc) {
+ document.addEventListener("keydown", execCommand("copy", aSucc));
+ sendString("Q");
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ false,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ case 2:
+ // Not triggered by user gesture
+ cutCopyAll(
+ function doCut(aSucc) {
+ is(
+ false,
+ document.execCommand("cut"),
+ "Can't directly execCommand not in a user callback"
+ );
+ },
+ function doCopy(aSucc) {
+ is(
+ false,
+ document.execCommand("copy"),
+ "Can't directly execCommand not in a user callback"
+ );
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ true,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ /** Test for Bug 1597857 **/
+ case 3:
+ // Button issued async
+ cutCopyAll(
+ function docut(aSucc) {
+ document.addEventListener(
+ "keydown",
+ execCommand("cut", aSucc, true)
+ );
+ sendString("Q");
+ },
+ function docopy(aSucc) {
+ document.addEventListener(
+ "keydown",
+ execCommand("copy", aSucc, true)
+ );
+ sendString("Q");
+ },
+ function done() {
+ testStep(n + 1);
+ },
+ false,
+ aClipOverride,
+ aNegateAll
+ );
+ return;
+
+ default:
+ aCb();
+ }
+ }
+ testStep(0);
+}
+
+// Run the tests
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestLongerTimeout(5); // On the emulator - this times out occasionally
+SimpleTest.waitForFocus(function () {
+ function justCancel(aEvent) {
+ aEvent.preventDefault();
+ }
+
+ function override(aEvent) {
+ aEvent.clipboardData.setData("text/plain", "overridden");
+ aEvent.preventDefault();
+ }
+
+ allMechanisms(function () {
+ gTestN0 = 1;
+ document.addEventListener("cut", override);
+ document.addEventListener("copy", override);
+
+ allMechanisms(function () {
+ gTestN0 = 2;
+ document.removeEventListener("cut", override);
+ document.removeEventListener("copy", override);
+ document.addEventListener("cut", justCancel);
+ document.addEventListener("copy", justCancel);
+
+ allMechanisms(
+ function () {
+ SimpleTest.finish();
+ },
+ null,
+ true
+ );
+ }, "overridden");
+ });
+});
diff --git a/dom/base/test/useractivation/file_empty.html b/dom/base/test/useractivation/file_empty.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/base/test/useractivation/file_empty.html
diff --git a/dom/base/test/useractivation/file_iframe_check_user_activation.html b/dom/base/test/useractivation/file_iframe_check_user_activation.html
new file mode 100644
index 0000000000..0a3ec734a6
--- /dev/null
+++ b/dom/base/test/useractivation/file_iframe_check_user_activation.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>user activated iframe</title>
+</head>
+<body>
+<script>
+onload = function() {
+ parent.postMessage("loaded", "*");
+};
+onmessage = function(e) {
+ if (e.data === "get") {
+ parent.postMessage({
+ isActivated: SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ hasBeenActivated: SpecialPowers.wrap(document).hasBeenUserGestureActivated,
+ lastActivationTimestamp: SpecialPowers.wrap(document).lastUserGestureTimeStamp,
+ }, "*");
+ }
+};
+</script>
+</body>
+</html>
diff --git a/dom/base/test/useractivation/file_iframe_consume_user_activation.html b/dom/base/test/useractivation/file_iframe_consume_user_activation.html
new file mode 100644
index 0000000000..ad27453f1a
--- /dev/null
+++ b/dom/base/test/useractivation/file_iframe_consume_user_activation.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>user activated iframe</title>
+</head>
+<body>
+<script>
+onload = function() {
+ SpecialPowers.wrap(document).notifyUserGestureActivation();
+ SpecialPowers.wrap(document).consumeTransientUserGestureActivation();
+ parent.postMessage("done", "*");
+}
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/useractivation/file_iframe_user_activated.html b/dom/base/test/useractivation/file_iframe_user_activated.html
new file mode 100644
index 0000000000..8d188001e8
--- /dev/null
+++ b/dom/base/test/useractivation/file_iframe_user_activated.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>user activated iframe</title>
+</head>
+<body>
+<script>
+onload = function() {
+ SpecialPowers.wrap(document).notifyUserGestureActivation();
+ parent.postMessage("done", "*");
+}
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/base/test/useractivation/file_useractivation_sandbox_transient_popup.html b/dom/base/test/useractivation/file_useractivation_sandbox_transient_popup.html
new file mode 100644
index 0000000000..25bc2037c3
--- /dev/null
+++ b/dom/base/test/useractivation/file_useractivation_sandbox_transient_popup.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>User activation popup</title>
+</head>
+<body>
+<iframe sandbox="allow-top-navigation-by-user-activation allow-scripts allow-same-origin"></iframe>
+<script>
+ window.addEventListener("message", (e) => {
+ if (e.data === "triggerIframeLoad") {
+ // Load into the the iframe a script which notifies the opener of top level navigation or if it was prevented.
+ let script = `window.opener.postMessage("topNavigation");`;
+ frames[0].frameElement.src = `javascript:try{window.top.location='javascript:${encodeURIComponent(script)}';} catch (e) {window.top.opener.postMessage("topNavigationBlocked");}`;
+ } else {
+ window.opener.postMessage("unexpected");
+ }
+ });
+</script>
+</body>
+</html>
diff --git a/dom/base/test/useractivation/mochitest.ini b/dom/base/test/useractivation/mochitest.ini
new file mode 100644
index 0000000000..26c8594be8
--- /dev/null
+++ b/dom/base/test/useractivation/mochitest.ini
@@ -0,0 +1,23 @@
+[DEFAULT]
+support-files =
+ file_empty.html
+ file_iframe_user_activated.html
+ file_iframe_check_user_activation.html
+ file_iframe_consume_user_activation.html
+ file_clipboard_common.js
+prefs =
+ formhelper.autozoom.force-disable.test-only=true
+
+[test_useractivation_has_been_activated.html]
+[test_useractivation_key_events.html]
+[test_useractivation_transient.html]
+[test_useractivation_sandbox_transient.html]
+support-files = file_useractivation_sandbox_transient_popup.html
+[test_useractivation_scrollbar.html]
+skip-if = os == 'android' # scrollbar not showed on mobile
+[test_useractivation_transient_consuming.html]
+[test_clipboard_editor.html]
+[test_clipboard_noeditor.html]
+[test_popup_blocker_mouse_event.html]
+[test_popup_blocker_pointer_event.html]
+[test_popup_blocker_async_callback.html]
diff --git a/dom/base/test/useractivation/moz.build b/dom/base/test/useractivation/moz.build
new file mode 100644
index 0000000000..60b508c774
--- /dev/null
+++ b/dom/base/test/useractivation/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += [
+ "mochitest.ini",
+]
diff --git a/dom/base/test/useractivation/test_clipboard_editor.html b/dom/base/test/useractivation/test_clipboard_editor.html
new file mode 100644
index 0000000000..691e8e4a20
--- /dev/null
+++ b/dom/base/test/useractivation/test_clipboard_editor.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1012662
+https://bugzilla.mozilla.org/show_bug.cgi?id=1597857
+-->
+<head>
+ <title>Test for Clipboard</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=1012662">Mozilla Bug 1012662</a><br>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1597857">Mozilla Bug 1597857</a>
+<p id="display"></p>
+
+<div id="content">
+ <span>span text</span>
+ <input type="text" value="text text">
+ <input type="password" value="password text">
+ <textarea>textarea text</textarea>
+ <div contentEditable="true">contenteditable text</div>
+</div>
+
+<pre id="test">
+<script type="application/javascript" src="file_clipboard_common.js"></script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/useractivation/test_clipboard_noeditor.html b/dom/base/test/useractivation/test_clipboard_noeditor.html
new file mode 100644
index 0000000000..f7f3d6cb99
--- /dev/null
+++ b/dom/base/test/useractivation/test_clipboard_noeditor.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1012662
+-->
+<head>
+ <title>Test for Clipboard</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=1012662">Mozilla Bug 1012662</a><br>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1597857">Mozilla Bug 1597857</a>
+<p id="display"></p>
+
+<div id="content">
+ <span>span text</span>
+ <input type="text" value="text text">
+ <input type="password" value="password text">
+ <textarea>textarea text</textarea>
+</div>
+
+<pre id="test">
+<script type="application/javascript" src="file_clipboard_common.js"></script>
+</pre>
+</body>
+</html>
diff --git a/dom/base/test/useractivation/test_popup_blocker_async_callback.html b/dom/base/test/useractivation/test_popup_blocker_async_callback.html
new file mode 100644
index 0000000000..dc53596531
--- /dev/null
+++ b/dom/base/test/useractivation/test_popup_blocker_async_callback.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering popup by mouse 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>
+<div id="target" style="width: 50px; height: 50px; background: green"></div>
+<script>
+
+SimpleTest.requestFlakyTimeout("Need to test setTimeout");
+
+function startTest(aTestAsyncFun, aAllowPopup = true) {
+ return new Promise(aResolve => {
+ let target = document.getElementById("target");
+ target.addEventListener("click", (e) => {
+ aTestAsyncFun(() => {
+ let w = window.open("about:blank");
+ is(!!w, aAllowPopup, `Should ${aAllowPopup ? "allow" : "block"} popup`);
+ if (w) {
+ w.close();
+ }
+ aResolve();
+ });
+ }, {once: true});
+ synthesizeMouseAtCenter(target, {type: "mousedown"});
+ synthesizeMouseAtCenter(target, {type: "mouseup"});
+ });
+}
+
+add_setup(async function() {
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["dom.disable_open_during_load", true],
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+ ]});
+});
+
+[
+ // setTimeout
+ function testSetTimout(aCallback) {
+ setTimeout(aCallback, 500);
+ },
+ // fetch
+ function testFetch(aCallback) {
+ fetch("../dummy.html").then(aCallback);
+ },
+ // requestStorageAccess
+ function testRequestStorageAccess(aCallback) {
+ document.requestStorageAccess().then(aCallback);
+ },
+ // serviceWorker.getRegistration
+ function testGetServiceWorkerRegistration(aCallback) {
+ navigator.serviceWorker.getRegistration("/app").then(aCallback);
+ },
+].forEach(testAsyncFun => {
+ add_task(async function() {
+ info(`start ${testAsyncFun.name}`);
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ await startTest(testAsyncFun);
+ await new Promise(aResolve => SimpleTest.executeSoon(aResolve));
+ });
+});
+
+// Test popup should be blocked if user transient is timeout
+add_task(async function timeout() {
+ info(`start user transient timeout`);
+ await SpecialPowers.pushPrefEnv({"set": [
+ ["dom.user_activation.transient.timeout", 1000],
+ ]});
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ await startTest((aCallback) => {
+ setTimeout(aCallback, 2000);
+ }, false);
+ await new Promise(aResolve => SimpleTest.executeSoon(aResolve));
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/base/test/useractivation/test_popup_blocker_mouse_event.html b/dom/base/test/useractivation/test_popup_blocker_mouse_event.html
new file mode 100644
index 0000000000..fd94150f1e
--- /dev/null
+++ b/dom/base/test/useractivation/test_popup_blocker_mouse_event.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for triggering popup by mouse 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>
+<div id="target" style="width: 50px; height: 50px; background: green"></div>
+<script>
+
+function sendMouseEvent(element, eventName, button, listenEventName, handler) {
+ let needToCheckHandler = false;
+ let handlerIsCalled = false;
+ if (listenEventName && handler) {
+ needToCheckHandler = true;
+ element.addEventListener(listenEventName, (e) => {
+ handler(e);
+ handlerIsCalled = true;
+ }, {once: true});
+ }
+ synthesizeMouseAtCenter(element, {type: eventName, button});
+ if (needToCheckHandler) {
+ ok(handlerIsCalled, "Handler should be called");
+ }
+}
+
+function checkAllowOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(w, `Should allow popup in the ${e.type} listener with button=${e.button}`);
+ if (w) {
+ w.close();
+ }
+}
+
+function checkBlockOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(!w, `Should block popup in the ${e.type} listener with button=${e.button}`);
+ if (w) {
+ w.close();
+ }
+}
+
+add_setup(async function() {
+ const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
+ let xorigin = SimpleTest.getTestFileURL("").replace(location.hostname, 'mochi.xorigin-test');
+ await SpecialPowers.pushPermissions([
+ {'type': 'popup', 'allow': DENY_ACTION,
+ 'context': document},
+ {'type': 'popup', 'allow': DENY_ACTION,
+ 'context': xorigin}
+ ]);
+
+ await new Promise(resolve => SimpleTest.waitForFocus(resolve));
+});
+
+const LEFT_BUTTON = 0;
+const MIDDLE_BUTTON = 1;
+const RIGHT_BUTTON = 2;
+let target = document.getElementById("target");
+
+add_task(function testMouseDownUpMove() {
+ // Left button
+ sendMouseEvent(target, "mousedown", LEFT_BUTTON, "mousedown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", LEFT_BUTTON, "mousemove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", LEFT_BUTTON, "mouseup", checkAllowOpenPopup);
+
+ // Middle button
+ sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "mousedown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "mousemove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "mouseup", checkAllowOpenPopup);
+
+ // Right button
+ sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "mousedown", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "mousemove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "mouseup", checkBlockOpenPopup);
+});
+
+add_task(function testMouseClick() {
+ // Left button
+ sendMouseEvent(target, "mousedown", LEFT_BUTTON);
+ sendMouseEvent(target, "mouseup", LEFT_BUTTON, "click", checkAllowOpenPopup);
+});
+
+add_task(function testMouseAuxclick() {
+ // Middle button
+ sendMouseEvent(target, "mousedown", MIDDLE_BUTTON);
+ sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "auxclick", checkAllowOpenPopup);
+
+ // Right button
+ sendMouseEvent(target, "mousedown", RIGHT_BUTTON);
+ sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "auxclick", checkAllowOpenPopup);
+});
+</script>
+</body>
+</html>
diff --git a/dom/base/test/useractivation/test_popup_blocker_pointer_event.html b/dom/base/test/useractivation/test_popup_blocker_pointer_event.html
new file mode 100644
index 0000000000..8d0b2c8cd1
--- /dev/null
+++ b/dom/base/test/useractivation/test_popup_blocker_pointer_event.html
@@ -0,0 +1,122 @@
+<!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>
+ <div id="target" style="width: 50px; height: 50px; background: green"></div>
+ <script>
+
+ function sendMouseEvent(element, eventName, button, listenEventName, handler) {
+ let needToCheckHandler = false;
+ let handlerIsCalled = false;
+ if (listenEventName && handler) {
+ needToCheckHandler = true;
+ element.addEventListener(listenEventName, (e) => {
+ handler(e);
+ handlerIsCalled = true;
+ }, {once: true});
+ }
+ synthesizeMouseAtCenter(element, {type: eventName, button});
+ if (needToCheckHandler) {
+ ok(handlerIsCalled, "Handler should be called");
+ }
+ }
+
+ function checkAllowOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(w, `Should allow popup in the ${e.type} listener with button=${e.button}`);
+ if (w) {
+ w.close();
+ }
+ }
+
+ function checkBlockOpenPopup(e) {
+ let w = window.open("about:blank");
+ ok(!w, `Should block popup in the ${e.type} listener with button=${e.button}`);
+ if (w) {
+ w.close();
+ }
+ }
+
+ add_setup(async function() {
+ const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
+ let xorigin = SimpleTest.getTestFileURL("").replace(location.hostname, 'mochi.xorigin-test');
+ await SpecialPowers.pushPermissions([
+ {'type': 'popup', 'allow': DENY_ACTION,
+ 'context': document},
+ {'type': 'popup', 'allow': DENY_ACTION,
+ 'context': xorigin}
+ ]);
+ await new Promise(resolve => SimpleTest.waitForFocus(resolve));
+ });
+
+ const LEFT_BUTTON = 0;
+ const MIDDLE_BUTTON = 1;
+ const RIGHT_BUTTON = 2;
+ let target = document.getElementById("target");
+
+ add_task(function testPointerEventDefault() {
+ // By default, only allow opening popup in the pointerup listener.
+ // Left button
+ sendMouseEvent(target, "mousedown", LEFT_BUTTON, "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", LEFT_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", LEFT_BUTTON, "pointerup", checkAllowOpenPopup);
+
+ // Middle button
+ sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "pointerup", checkAllowOpenPopup);
+
+ // Right button
+ sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "pointerdown", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "pointerup", checkBlockOpenPopup);
+ });
+
+ add_task(async function testPointerEventAddPointerDownToPref() {
+ // Adding pointerdown to preference
+ await SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
+ "pointerdown pointerup"]]});
+ // Left button
+ sendMouseEvent(target, "mousedown", LEFT_BUTTON, "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", LEFT_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", LEFT_BUTTON, "pointerup", checkAllowOpenPopup);
+
+ // Middle button
+ sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "pointerup", checkAllowOpenPopup);
+
+ // Right button
+ sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "pointerdown", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "pointerup", checkBlockOpenPopup);
+ });
+
+ add_task(async function testPointerEventAddPointerMoveToPref() {
+ // Adding pointermove to preference should have no effect.
+ await SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
+ "pointerdown pointerup pointermove"]]});
+ // Left button
+ sendMouseEvent(target, "mousedown", LEFT_BUTTON, "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", LEFT_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", LEFT_BUTTON, "pointerup", checkAllowOpenPopup);
+
+ // Middle button
+ sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "pointerdown", checkAllowOpenPopup);
+ sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "pointerup", checkAllowOpenPopup);
+
+ // Right button
+ sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "pointerdown", checkBlockOpenPopup);
+ sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "pointermove", checkBlockOpenPopup);
+ sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "pointerup", checkBlockOpenPopup);
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/base/test/useractivation/test_useractivation_has_been_activated.html b/dom/base/test/useractivation/test_useractivation_has_been_activated.html
new file mode 100644
index 0000000000..f46618915b
--- /dev/null
+++ b/dom/base/test/useractivation/test_useractivation_has_been_activated.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>User activation test: has been user gesture activated</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>
+<iframe></iframe>
+<iframe></iframe>
+<script>
+
+function waitForEvent(aTarget, aEvent, aCallback) {
+ return new Promise((aResolve) => {
+ aTarget.addEventListener(aEvent, function listener(event) {
+ aCallback(event);
+ aResolve();
+ }, { once: true });
+ });
+}
+
+let [iframe0, iframe1] = document.querySelectorAll("iframe");
+
+function doCheck(aDocument, aName, aHasBeenUserGestureActivated) {
+ is(SpecialPowers.wrap(aDocument).hasBeenUserGestureActivated,
+ aHasBeenUserGestureActivated,
+ `check has-been-user-activated on the ${aName}`);
+ if (aHasBeenUserGestureActivated) {
+ ok(SpecialPowers.wrap(aDocument).lastUserGestureTimeStamp > 0,
+ `check last-user-gesture-timestamp on the ${aName}`);
+ } else {
+ is(SpecialPowers.wrap(aDocument).lastUserGestureTimeStamp, 0,
+ `check last-user-gesture-timestamp on the ${aName}`);
+ }
+}
+
+add_task(async function checkInitialStatus() {
+ doCheck(document, "top-level document", false);
+ doCheck(frames[0].document, "first iframe", false);
+ doCheck(frames[1].document, "second iframe", false);
+});
+
+add_task(async function triggerUserActivation() {
+ // Trigger user activation on the first iframe.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+ // We should also propagate to all the ancestors.
+ doCheck(document, "top-level document", true);
+ doCheck(frames[0].document, "first iframe", true);
+ doCheck(frames[1].document, "second iframe", false);
+});
+
+add_task(async function iframeNavigation() {
+ frames[0].frameElement.src = "file_empty.html";
+ await waitForEvent(frames[0].frameElement, "load", () => {});
+ // We should reset the flag on iframe that navigates away from current page,
+ // but the flag on its ancestor isn't changed.
+ doCheck(document, "top-level document", true);
+ doCheck(frames[0].document, "first iframe", false);
+ doCheck(frames[1].document, "second iframe", false);
+});
+
+add_task(async function triggerUserActivationOnCrossOriginFrame() {
+ // Reset the activation flag.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ doCheck(document, "top-level document", false);
+
+ // load cross-origin test page on iframe.
+ frames[0].frameElement.src = "https://example.com/tests/dom/base/test/useractivation/file_iframe_user_activated.html";
+ await waitForEvent(window, "message", (event) => {
+ if (event.data === "done") {
+ doCheck(document, "top-level document", true);
+ doCheck(frames[1].document, "second iframe", false);
+ } else {
+ ok(false, "receive unexpected message: " + event.data);
+ }
+ });
+});
+
+add_task(async function propagateToSameOriginConnectedSubframe() {
+ // Reset the activation flag.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+
+ // load cross-origin test page on iframe.
+ iframe0.src = "https://example.com/tests/dom/base/test/useractivation/file_iframe_check_user_activation.html";
+ await waitForEvent(window, "message", (event) => {
+ if (event.data !== "loaded") {
+ ok(false, "receive unexpected message: " + event.data);
+ }
+ });
+
+ // Trigger user activation on top-level document.
+ SpecialPowers.wrap(document).notifyUserGestureActivation();
+ doCheck(document, "top-level document", true);
+ doCheck(iframe1.contentDocument, "second iframe", true);
+
+ iframe0.contentWindow.postMessage("get", "*");
+ await waitForEvent(window, "message", (event) => {
+ if (typeof event.data === "object") {
+ ok(!event.data.hasBeenActivated, "check has-been-user-activated on the first iframe");
+ is(event.data.lastActivationTimestamp, 0, "check last-user-gesture-timestamp on the first iframe");
+ } else {
+ ok(false, "receive unexpected message: " + event.data);
+ }
+ });
+});
+
+add_task(async function endTests() {
+ // Reset the activation flag in order not to interfere following test in the
+ // verify mode which would run the test using same document couple times.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+});
+
+</script>
+</body>
diff --git a/dom/base/test/useractivation/test_useractivation_key_events.html b/dom/base/test/useractivation/test_useractivation_key_events.html
new file mode 100644
index 0000000000..d97906c22b
--- /dev/null
+++ b/dom/base/test/useractivation/test_useractivation_key_events.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>User activation test: key 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>
+
+function synthesizeKeyAndWait(aKey, aEvent) {
+ let promise = new Promise(aResolve => {
+ document.addEventListener("keydown", function(e) {
+ e.preventDefault();
+ aResolve();
+ }, { once: true });
+ });
+ synthesizeKey(aKey, aEvent, window);
+ return promise;
+}
+
+add_task(async function TestPrintableKey() {
+ let tests = [ 'a', 'b', 'c', 'A', 'B', '1', '2', '3' ];
+
+ for (let key of tests) {
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ await synthesizeKeyAndWait(key, {});
+ ok(SpecialPowers.wrap(document).hasBeenUserGestureActivated,
+ `check has-been-user-activated for ${key}`);
+ ok(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ `check has-valid-transient-user-activation for ${key}`);
+ }
+});
+
+add_task(async function TestNonPrintableKey() {
+ let tests = [ [ "KEY_Alt", false],
+ [ "KEY_Backspace", false],
+ [ "KEY_Escape" , false ],
+ [ "KEY_Tab" , false ],
+ // Treat as user input
+ [ "KEY_Enter", true],
+ [ " ", true] ];
+
+ for (let [key, expectedResult] of tests) {
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ await synthesizeKeyAndWait(key, {});
+ is(SpecialPowers.wrap(document).hasBeenUserGestureActivated, expectedResult,
+ `check has-been-user-activated for "${key}"`);
+ is(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation, expectedResult,
+ `check has-valid-transient-user-activation for "${key}"`);
+ }
+});
+
+add_task(async function TestModifier() {
+ let tests = [ [ 'a', { altKey: true }, false],
+ [ 'a', { ctrlKey: true }, false],
+ [ 'a', { metaKey: true }, false],
+ [ 'a', { osKey: true }, false],
+ [ 'c', { altKey: true }, false ],
+ [ 'c', { osKey: true }, false ],
+ [ 'v', { altKey: true }, false ],
+ [ 'v', { osKey: true }, false ],
+ [ 'x', { altKey: true }, false ],
+ [ 'x', { osKey: true }, false ],
+ // Treat as user input
+ [ 'a', { altGraphKey: true }, true ],
+ [ 'a', { fnKey: true }, true ],
+ [ 'a', { shiftKey: true }, true ],
+ [ 'c', { accelKey: true }, true ],
+ [ 'v', { accelKey: true }, true ],
+ [ 'x', { accelKey: true }, true ] ];
+
+ for (let [key, event, expectedResult] of tests) {
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ await synthesizeKeyAndWait(key, event);
+ is(SpecialPowers.wrap(document).hasBeenUserGestureActivated, expectedResult,
+ `check has-been-user-activated for ${key} with ${JSON.stringify(event)}`);
+ is(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation, expectedResult,
+ `check has-valid-transient-user-activation for ${key} with ${JSON.stringify(event)}`);
+ }
+});
+
+add_task(async function endTests() {
+ // Reset the activation flag in order not to interfere following test in the
+ // verify mode which would run the test using same document couple times.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+});
+
+</script>
+</body>
diff --git a/dom/base/test/useractivation/test_useractivation_sandbox_transient.html b/dom/base/test/useractivation/test_useractivation_sandbox_transient.html
new file mode 100644
index 0000000000..6b0fcb50f0
--- /dev/null
+++ b/dom/base/test/useractivation/test_useractivation_sandbox_transient.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>User activation test: transient flag</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.requestFlakyTimeout("Timeouts are needed to test transient user_activation");
+let timeout = SpecialPowers.getIntPref("dom.user_activation.transient.timeout") + 1000;
+
+function waitForEvent(aTarget, aEvent, aCallback) {
+ return new Promise((aResolve) => {
+ aTarget.addEventListener(aEvent, function listener(event) {
+ aCallback(event);
+ aResolve();
+ }, { once: true });
+ });
+}
+
+function checkPopupActivated(popup, activated) {
+ let state = activated ? "valid" : "invalid";
+ ok(activated === SpecialPowers.wrap(popup.document).hasValidTransientUserGestureActivation,
+ `check has-${state}-transient-user-activation on top-level document`);
+ ok(activated === SpecialPowers.wrap(popup.frames[0].document).hasValidTransientUserGestureActivation,
+ `check has-${state}-transient-user-activation on iframe`);
+}
+
+add_task(async function triggerUserActivation() {
+ let message = waitForEvent(window, "message", (e) => {
+ if (e.data === "topNavigation") {
+ ok(true, "Top navigation changed");
+ } else {
+ ok(false, "Unexpected message");
+ }
+ });
+ let popup = window.open("./file_useractivation_sandbox_transient_popup.html", "_blank");
+ await new Promise((r) => {
+ popup.addEventListener("load", r);
+ });
+ checkPopupActivated(popup, false);
+ // Create user gesture into iframe within popup just opened
+ SpecialPowers.wrap(popup.frames[0].frameElement.contentDocument).notifyUserGestureActivation();
+ checkPopupActivated(popup, true);
+ // Notify popup to load into the frame
+ popup.postMessage("triggerIframeLoad");
+ await message;
+ popup.close();
+});
+
+add_task(async function triggerUserActivationTimeout() {
+ let message = waitForEvent(window, "message", (e) => {
+ // Top navigation MUST be blocked
+ if (e.data === "topNavigationBlocked") {
+ ok(true, "Top navigation blocked");
+ } else {
+ ok(false, "Unexpected message");
+ }
+ });
+ let popup = window.open("./file_useractivation_sandbox_transient_popup.html", "_blank");
+ await new Promise((r) => {
+ popup.addEventListener("load", r);
+ });
+ checkPopupActivated(popup, false);
+ // Create user gesture into iframe within popup just opened
+ SpecialPowers.wrap(popup.frames[0].frameElement.contentDocument).notifyUserGestureActivation();
+ checkPopupActivated(popup, true);
+ // Ensure we timeout user gesture
+ await new Promise((aResolve) => {
+ setTimeout(() => {
+ checkPopupActivated(popup, false);
+ aResolve();
+ }, timeout);
+ });
+ // Notify popup to load into the frame
+ popup.postMessage("triggerIframeLoad");
+ await message;
+ popup.close();
+});
+
+add_task(async function endTests() {
+ // Reset the activation flag in order not to interfere following test in the
+ // verify mode which would run the test using same document couple times.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+});
+
+</script>
+</body>
diff --git a/dom/base/test/useractivation/test_useractivation_scrollbar.html b/dom/base/test/useractivation/test_useractivation_scrollbar.html
new file mode 100644
index 0000000000..778d6d0898
--- /dev/null
+++ b/dom/base/test/useractivation/test_useractivation_scrollbar.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>User activation test: consume transient flag</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>
+<textarea style="height: 100px; resize: none">
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+&nbsp
+</textarea>
+<div id="target" style="height: 100px; width: 200px; overflow: scroll">
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+&nbsp<br>
+</div>
+<div style="height: 2000px; width: 500px; background-color: green;"></div>
+<script>
+
+// Open a new window to ensure scrollbar is always visible.
+if (!opener) {
+ add_task(async function init() {
+ // Turn on the prefs that force overlay scrollbars to always be visible.
+ await SpecialPowers.pushPrefEnv({
+ set: [["layout.testing.overlay-scrollbars.always-visible", true]],
+ });
+ });
+
+ async function testOnNewWindow(aPrefValue) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.user_activation.ignore_scrollbars", aPrefValue]],
+ });
+
+ let win = window.open(location);
+ // wait for message
+ await new Promise((aResolve) => {
+ window.addEventListener("message", function listener(event) {
+ if ("done" == event.data) {
+ window.removeEventListener("message", listener);
+ aResolve();
+ }
+ });
+ });
+ win.close();
+ }
+
+ add_task(async function test_pref_on() {
+ await testOnNewWindow(true);
+ });
+
+ add_task(async function test_pref_off() {
+ await testOnNewWindow(false);
+ });
+} else {
+ SimpleTest.waitForFocus(async function() {
+ function waitForEvent(aTarget, aEvent) {
+ return new Promise((aResolve) => {
+ aTarget.addEventListener(aEvent, function listener(event) {
+ aResolve();
+ }, { once: true });
+ });
+ }
+
+ let ignoreScrollbars = SpecialPowers.getBoolPref("dom.user_activation.ignore_scrollbars");
+
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ let textarea = document.querySelector("textarea");
+ var rect = textarea.getBoundingClientRect();
+
+ // click scrollbar of textarea
+ let promise = waitForEvent(textarea, "scroll");
+ synthesizeMouse(textarea, rect.width - 5, rect.height / 2, {});
+ await promise;
+
+ opener.is(SpecialPowers.wrap(document).hasBeenUserGestureActivated,
+ !ignoreScrollbars, "check has-been-user-activated");
+ opener.is(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ !ignoreScrollbars, "check has-valid-transient-user-activation");
+
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ let div = document.querySelector("div[id=target]");
+ rect = div.getBoundingClientRect();
+
+ // click scrollbar of div
+ promise = waitForEvent(div, "scroll");
+ synthesizeMouse(div, rect.width - 5, rect.height / 2, {});
+ await promise;
+
+ opener.is(SpecialPowers.wrap(document).hasBeenUserGestureActivated,
+ !ignoreScrollbars, "check has-been-user-activated");
+ opener.is(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ !ignoreScrollbars, "check has-valid-transient-user-activation");
+
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+ let body = document.querySelector("body");
+
+ // click scrollbar of page
+ promise = waitForEvent(document, "scroll");
+ synthesizeMouse(body, innerWidth - 10, innerHeight / 2, {});
+ await promise;
+
+ opener.is(SpecialPowers.wrap(document).hasBeenUserGestureActivated,
+ !ignoreScrollbars, "check has-been-user-activated");
+ opener.is(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ !ignoreScrollbars, "check has-valid-transient-user-activation");
+
+ opener.postMessage("done", "*");
+ }, window);
+}
+
+</script>
+</body>
diff --git a/dom/base/test/useractivation/test_useractivation_transient.html b/dom/base/test/useractivation/test_useractivation_transient.html
new file mode 100644
index 0000000000..d3148e5d1d
--- /dev/null
+++ b/dom/base/test/useractivation/test_useractivation_transient.html
@@ -0,0 +1,155 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>User activation test: transient flag</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>
+<iframe></iframe>
+<iframe></iframe>
+<script>
+
+SimpleTest.requestFlakyTimeout("Timeouts are needed to test transient user_activation");
+
+let timeout = SpecialPowers.getIntPref("dom.user_activation.transient.timeout") + 1000;
+let [iframe0, iframe1] = document.querySelectorAll("iframe");
+
+function waitForEvent(aTarget, aEvent, aCallback) {
+ return new Promise((aResolve) => {
+ aTarget.addEventListener(aEvent, function listener(event) {
+ aCallback(event);
+ aResolve();
+ }, { once: true });
+ });
+}
+
+add_task(async function checkInitialStatus() {
+ ok(!SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on top-level document");
+ ok(!SpecialPowers.wrap(frames[0].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on first iframe");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on second iframe");
+});
+
+add_task(async function triggerUserActivation() {
+ // Trigger user activation on the first iframe.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+
+ // We should also propagate to all the ancestors.
+ ok(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(SpecialPowers.wrap(frames[0].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the first iframe");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+});
+
+add_task(async function iframeNavigation() {
+ frames[0].frameElement.src = "file_empty.html";
+ await waitForEvent(frames[0].frameElement, "load", () => {});
+ // We should reset the flag on iframe that navigates away from current page,
+ // but the flag on its ancestor isn't changed.
+ ok(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(!SpecialPowers.wrap(frames[0].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the first iframe");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+});
+
+add_task(async function triggerUserActivationTimeout() {
+ // Trigger user activation on the first iframe.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+
+ // hasValidTransientUserGestureActivation should return false after timeout.
+ await new Promise((aResolve) => {
+ setTimeout(() => {
+ ok(!SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(!SpecialPowers.wrap(frames[0].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the first iframe");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+ aResolve();
+ }, timeout);
+ });
+
+ // Trigger user activation again.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+ ok(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(SpecialPowers.wrap(frames[0].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the first iframe");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+});
+
+add_task(async function triggerUserActivationOnCrossOriginFrame() {
+ // Reset the activation flag.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+
+ // load cross-origin test page on iframe.
+ frames[0].frameElement.src = "https://example.com/tests/dom/base/test/useractivation/file_iframe_user_activated.html";
+ await waitForEvent(window, "message", (event) => {
+ if (event.data === "done") {
+ ok(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+ } else {
+ ok(false, "receive unexpected message: " + event.data);
+ }
+ });
+
+ // hasValidTransientUserGestureActivation should return false after timeout.
+ await new Promise((aResolve) => {
+ setTimeout(() => {
+ ok(!SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+ aResolve();
+ }, timeout);
+ });
+});
+
+add_task(async function propagateToSameOriginConnectedSubframe() {
+ // Reset the activation flag.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+
+ // load cross-origin test page on iframe.
+ iframe0.src = "https://example.com/tests/dom/base/test/useractivation/file_iframe_check_user_activation.html";
+ await waitForEvent(window, "message", (event) => {
+ if (event.data !== "loaded") {
+ ok(false, "receive unexpected message: " + event.data);
+ }
+ });
+
+ // Trigger user activation on top-level document.
+ SpecialPowers.wrap(document).notifyUserGestureActivation();
+ ok(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(SpecialPowers.wrap(iframe1.contentDocument).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+
+ iframe0.contentWindow.postMessage("get", "*");
+ await waitForEvent(window, "message", (event) => {
+ if (typeof event.data === "object") {
+ ok(!event.data.isActivated, "check has-valid-transient-user-activation on the first iframe");
+ } else {
+ ok(false, "receive unexpected message: " + event.data);
+ }
+ });
+});
+
+add_task(async function endTests() {
+ // Reset the activation flag in order not to interfere following test in the
+ // verify mode which would run the test using same document couple times.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+});
+
+</script>
+</body>
diff --git a/dom/base/test/useractivation/test_useractivation_transient_consuming.html b/dom/base/test/useractivation/test_useractivation_transient_consuming.html
new file mode 100644
index 0000000000..4178d24477
--- /dev/null
+++ b/dom/base/test/useractivation/test_useractivation_transient_consuming.html
@@ -0,0 +1,151 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>User activation test: consume transient flag</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>
+<iframe></iframe>
+<iframe></iframe>
+<script>
+
+SimpleTest.requestFlakyTimeout("Timeouts are needed to test transient user_activation");
+
+let timeout = SpecialPowers.getIntPref("dom.user_activation.transient.timeout") + 1000;
+
+function waitForEvent(aTarget, aEvent, aCallback) {
+ return new Promise((aResolve) => {
+ aTarget.addEventListener(aEvent, function listener(event) {
+ aCallback(event);
+ aResolve();
+ }, { once: true });
+ });
+}
+
+function doCheck(aDocument, aName, aHasBeenUserGestureActivated,
+ aHasValidTransientUserGestureActivation,
+ aLastUserGestureTimeStamp) {
+ is(SpecialPowers.wrap(aDocument).hasBeenUserGestureActivated,
+ aHasBeenUserGestureActivated,
+ `check has-been-user-activated on the ${aName}`);
+ is(SpecialPowers.wrap(aDocument).hasValidTransientUserGestureActivation,
+ aHasValidTransientUserGestureActivation,
+ `check has-valid-transient-user-activation on the ${aName}`);
+ is(SpecialPowers.wrap(aDocument).lastUserGestureTimeStamp,
+ aLastUserGestureTimeStamp,
+ `check last-user-gesture-timestamp on the ${aName}`);
+}
+
+add_task(async function checkInitialStatus() {
+ doCheck(document, "top-level document", false, false, 0);
+ ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on top-level document");
+
+ doCheck(frames[0].document, "first iframe", false, false, 0);
+ ok(!SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on first iframe");
+
+ doCheck(frames[1].document, "second iframe", false, false, 0);
+ ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on second iframe");
+});
+
+add_task(async function consumeTransientUserActivation() {
+ // Trigger user activation on the first iframe.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+ let lastTimeStampTop = SpecialPowers.wrap(document).lastUserGestureTimeStamp;
+ let lastTimeStampFirst = SpecialPowers.wrap(frames[0].document).lastUserGestureTimeStamp;
+
+ // Try to consume transient user activation.
+ ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on second iframe");
+ ok(SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on first iframe");
+ // Consuming a transient-user-activation should affect all tree.
+ ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on top-level document");
+
+ // Check has-valid-transient-user-activation and should not affect
+ // has-been-user-activated
+ doCheck(document, "top-level document", true, false, lastTimeStampTop);
+ doCheck(frames[0].document, "first iframe", true, false, lastTimeStampFirst);
+ doCheck(frames[1].document, "second iframe", false, false, 0);
+});
+
+add_task(async function consumeTransientUserActivationTimeout() {
+ // Trigger user activation on the first iframe.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+
+ // Should not able to consume successfully after timeout.
+ await new Promise((aResolve) => {
+ setTimeout(() => {
+ ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on top-level document");
+ ok(!SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on first iframe");
+ ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on second iframe");
+ aResolve();
+ }, timeout);
+ });
+
+ // Trigger user activation again.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+
+ // Try to consume transient user activation.
+ ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on second iframe");
+ ok(SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on first iframe");
+ // Consuming a transient-user-activation should affect all tree.
+ ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on top-level document");
+});
+
+add_task(async function iframeNavigation() {
+ // Trigger user activation on the first iframe.
+ SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
+
+ // Navigate away from current page.
+ frames[0].frameElement.src = "file_empty.html";
+ await waitForEvent(frames[0].frameElement, "load", () => {});
+
+ // Try to consume transient user activation.
+ ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on second iframe");
+ ok(!SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on first iframe");
+ ok(SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on top-level document");
+});
+
+add_task(async function triggerUserActivationOnCrossOriginFrame() {
+ // Reset the activation flag.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+
+ // load cross-origin test page on iframe.
+ frames[0].frameElement.src = "https://example.com/tests/dom/base/test/useractivation/file_iframe_consume_user_activation.html";
+ await waitForEvent(window, "message", (event) => {
+ if (event.data === "done") {
+ ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
+ "consume transient-user-activation on top-level document");
+ ok(!SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the top-level document");
+ ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
+ "check has-valid-transient-user-activation on the second iframe");
+ } else {
+ ok(false, "receive unexpected message: " + event.data);
+ }
+ });
+});
+
+add_task(async function endTests() {
+ // Reset the activation flag in order not to interfere following test in the
+ // verify mode which would run the test using same document couple times.
+ SpecialPowers.wrap(document).clearUserGestureActivation();
+});
+
+</script>
+</body>
diff --git a/dom/base/test/variable_style_sheet.sjs b/dom/base/test/variable_style_sheet.sjs
new file mode 100644
index 0000000000..8e4848a7f4
--- /dev/null
+++ b/dom/base/test/variable_style_sheet.sjs
@@ -0,0 +1,18 @@
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/css", false);
+
+ var accessCount;
+ var state = getState("varSSAccessCount");
+ if (!state) {
+ setState("varSSAccessCount", "0");
+ accessCount = 0;
+ } else {
+ setState("varSSAccessCount", (parseInt(state) + 1).toString());
+ accessCount = parseInt(state) + 1;
+ }
+
+ response.write(
+ "#content { background-color: rgb(" + (accessCount % 256) + ", 0, 0); }"
+ );
+}
diff --git a/dom/base/test/w3element_traversal.svg b/dom/base/test/w3element_traversal.svg
new file mode 100644
index 0000000000..86e4292d6d
--- /dev/null
+++ b/dom/base/test/w3element_traversal.svg
@@ -0,0 +1,70 @@
+<!DOCTYPE svg
+[
+<!ENTITY tree "<tspan id='first_element_child_entity'></tspan>">
+]>
+
+<svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:pickle="http://ns.example.org/pickle"
+ version="1.1"
+ width="100%" height="100%" viewBox="0 0 400 400">
+
+ <text >
+ <tspan id="first_element_child_namespace"></tspan>
+ </text>
+ <g id="parentEl_namespace">
+ <pickle:dill />
+ </g>
+
+ <text id="parentEl_pes" >
+ <tspan id="first_element_child_pes"></tspan>
+ <tspan id="middle_element_child_pes"></tspan>
+ <tspan id="last_element_child_pes"></tspan>
+ </text>
+
+
+ <text id="parentEl" >
+ <tspan id="first_element_child_sibnull"></tspan>
+ </text>
+
+ <text id="parentEl_nes" >
+ <tspan id="first_element_child_nes"></tspan>
+ <tspan id="last_element_child_nes"></tspan>
+ </text>
+
+ <text id="parentEl_lec" >
+ <tspan id="first_element_child_lec"></tspan>
+ <tspan id="last_element_child_lec"></tspan>
+ </text>
+
+
+ <text id="parentEl_fec" >
+ <tspan id="first_element_child_fec"></tspan>
+ </text>
+
+ <text id="parentEl_entity" >&tree;</text>
+
+ <text id="parentEl_dynremove" >
+ <tspan id="first_element_child_dynremove"></tspan>
+ <tspan id="last_element_child_dynremove"></tspan>
+ </text>
+
+ <text id="parentEl_dynadd" >
+ <tspan id="first_element_child_dynadd"></tspan>
+ </text>
+
+ <text id="parentEl_null" ></text>
+
+ <text id="parentEl_count" >
+ <tspan id="first_element_child_count">
+ <tspan></tspan>
+ <tspan></tspan>
+ </tspan>
+ <tspan id="middle_element_child"></tspan>
+ <tspan id="last_element_child_count"></tspan>
+ </text>
+
+ <text id="parentEl_nochild"></text>
+
+</svg>
+
diff --git a/dom/base/test/wholeTexty-helper.xml b/dom/base/test/wholeTexty-helper.xml
new file mode 100644
index 0000000000..779a54c8b4
--- /dev/null
+++ b/dom/base/test/wholeTexty-helper.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE document
+ [
+ <!ENTITY foobar "baz<quux/>">
+ ]>
+<document><![CDATA[]]><entity>&foobar;</entity></document>
diff --git a/dom/base/test/worker_postMessages.js b/dom/base/test/worker_postMessages.js
new file mode 100644
index 0000000000..77bfa80748
--- /dev/null
+++ b/dom/base/test/worker_postMessages.js
@@ -0,0 +1,73 @@
+function test_workers() {
+ onmessage = function (e) {
+ postMessage(e.data, e.ports);
+ };
+
+ onmessageerror = function (e) {
+ postMessage("error");
+ };
+}
+
+function test_sharedWorkers(port) {
+ port.onmessage = function (e) {
+ if (e.data == "terminate") {
+ close();
+ } else {
+ port.postMessage(e.data, e.ports);
+ }
+ };
+
+ port.onmessageerror = function (e) {
+ port.postMessage("error");
+ };
+}
+
+function test_broadcastChannel(obj) {
+ var bc = new BroadcastChannel("postMessagesTest_inWorkers");
+ bc.onmessage = function (e) {
+ obj.postMessage(e.data);
+ };
+
+ bc.onmessageerror = function () {
+ obj.postMessage("error");
+ };
+}
+
+function test_messagePort(port) {
+ port.onmessage = function (e) {
+ postMessage(e.data, e.ports);
+ };
+
+ port.onmessageerror = function (e) {
+ postMessage("error");
+ };
+}
+
+onconnect = function (e) {
+ e.ports[0].onmessage = ee => {
+ if (ee.data == "sharedworkers") {
+ test_sharedWorkers(e.ports[0]);
+ e.ports[0].postMessage("ok");
+ } else if (ee.data == "broadcastChannel") {
+ test_broadcastChannel(e.ports[0]);
+ e.ports[0].postMessage("ok");
+ } else if (ee.data == "terminate") {
+ close();
+ }
+ };
+};
+
+onmessage = function (e) {
+ if (e.data == "workers") {
+ test_workers();
+ postMessage("ok");
+ } else if (e.data == "broadcastChannel") {
+ test_broadcastChannel(self);
+ postMessage("ok");
+ } else if (e.data == "messagePort") {
+ test_messagePort(e.ports[0]);
+ postMessage("ok");
+ } else {
+ postMessage("ko");
+ }
+};